line_printer.cpp revision c5b8ad88ce6e74216198f14c6e33d55cb1681370
1b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes// Copyright 2013 Google Inc. All Rights Reserved. 2b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes// 3b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes// Licensed under the Apache License, Version 2.0 (the "License"); 4b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes// you may not use this file except in compliance with the License. 5b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes// You may obtain a copy of the License at 6b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes// 7b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes// http://www.apache.org/licenses/LICENSE-2.0 8b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes// 9b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes// Unless required by applicable law or agreed to in writing, software 10b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes// distributed under the License is distributed on an "AS IS" BASIS, 11b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes// See the License for the specific language governing permissions and 13b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes// limitations under the License. 14b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes 15b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes#include "line_printer.h" 16b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes 17b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes#include <stdio.h> 18b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes#include <stdlib.h> 19b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes#ifdef _WIN32 20b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes#include <windows.h> 21b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes#else 22b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes#include <unistd.h> 23b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes#include <sys/ioctl.h> 24b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes#include <termios.h> 25b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes#include <sys/time.h> 26b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes#endif 27b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes 28b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes// Make sure printf is really adb_printf which works for UTF-8 on Windows. 29b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes#include <sysdeps.h> 30b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes 31b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes// Stuff from ninja's util.h that's needed below. 32b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes#include <vector> 33b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughesusing namespace std; 34b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughesstring ElideMiddle(const string& str, size_t width) { 35b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes const int kMargin = 3; // Space for "...". 36b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes string result = str; 37b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes if (result.size() + kMargin > width) { 38b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes size_t elide_size = (width - kMargin) / 2; 39b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes result = result.substr(0, elide_size) 40b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes + "..." 41b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes + result.substr(result.size() - elide_size, elide_size); 42b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes } 43b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes return result; 44b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes} 45b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes 46b708d1628332ea9266d08f0297cd9e9ee341a64fElliott HughesLinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) { 47b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes#ifndef _WIN32 48b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes const char* term = getenv("TERM"); 49c5b8ad88ce6e74216198f14c6e33d55cb1681370David Pursell smart_terminal_ = unix_isatty(1) && term && string(term) != "dumb"; 50b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes#else 51b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // Disable output buffer. It'd be nice to use line buffering but 52b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // MSDN says: "For some systems, [_IOLBF] provides line 53b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // buffering. However, for Win32, the behavior is the same as _IOFBF 54b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // - Full Buffering." 55b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes setvbuf(stdout, NULL, _IONBF, 0); 56b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes console_ = GetStdHandle(STD_OUTPUT_HANDLE); 57b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes CONSOLE_SCREEN_BUFFER_INFO csbi; 58b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes smart_terminal_ = GetConsoleScreenBufferInfo(console_, &csbi); 59b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes#endif 60b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes} 61b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes 62b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughesvoid LinePrinter::Print(string to_print, LineType type) { 63b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes if (console_locked_) { 64b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes line_buffer_ = to_print; 65b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes line_type_ = type; 66b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes return; 67b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes } 68b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes 69b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes if (smart_terminal_) { 70b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes printf("\r"); // Print over previous line, if any. 71b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // On Windows, calling a C library function writing to stdout also handles 72b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // pausing the executable when the "Pause" key or Ctrl-S is pressed. 73b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes } 74b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes 75b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes if (smart_terminal_ && type == ELIDE) { 76b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes#ifdef _WIN32 77b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes CONSOLE_SCREEN_BUFFER_INFO csbi; 78b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes GetConsoleScreenBufferInfo(console_, &csbi); 79b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes 80b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // TODO: const std::wstring to_print_wide = widen(to_print); 81b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // TODO: wstring ElideMiddle. 82b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes to_print = ElideMiddle(to_print, static_cast<size_t>(csbi.dwSize.X)); 83b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // We don't want to have the cursor spamming back and forth, so instead of 84b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // printf use WriteConsoleOutput which updates the contents of the buffer, 85b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // but doesn't move the cursor position. 86b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes COORD buf_size = { csbi.dwSize.X, 1 }; 87b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes COORD zero_zero = { 0, 0 }; 88b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes SMALL_RECT target = { 89b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes csbi.dwCursorPosition.X, csbi.dwCursorPosition.Y, 90b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes static_cast<SHORT>(csbi.dwCursorPosition.X + csbi.dwSize.X - 1), 91b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes csbi.dwCursorPosition.Y 92b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes }; 93b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes vector<CHAR_INFO> char_data(csbi.dwSize.X); 94b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes for (size_t i = 0; i < static_cast<size_t>(csbi.dwSize.X); ++i) { 95b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // TODO: UnicodeChar instead of AsciiChar, to_print_wide[i]. 96b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes char_data[i].Char.AsciiChar = i < to_print.size() ? to_print[i] : ' '; 97b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes char_data[i].Attributes = csbi.wAttributes; 98b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes } 99b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // TODO: WriteConsoleOutputW. 100b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes WriteConsoleOutput(console_, &char_data[0], buf_size, zero_zero, &target); 101b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes#else 102b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // Limit output to width of the terminal if provided so we don't cause 103b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // line-wrapping. 104b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes winsize size; 105b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes if ((ioctl(0, TIOCGWINSZ, &size) == 0) && size.ws_col) { 106b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes to_print = ElideMiddle(to_print, size.ws_col); 107b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes } 108b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes printf("%s", to_print.c_str()); 109b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes printf("\x1B[K"); // Clear to end of line. 110b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes fflush(stdout); 111b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes#endif 112b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes 113b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes have_blank_line_ = false; 114b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes } else { 115b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes printf("%s\n", to_print.c_str()); 116b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes } 117b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes} 118b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes 119b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughesvoid LinePrinter::PrintOrBuffer(const char* data, size_t size) { 120b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes if (console_locked_) { 121b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes output_buffer_.append(data, size); 122b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes } else { 123b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // Avoid printf and C strings, since the actual output might contain null 124b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // bytes like UTF-16 does (yuck). 125b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes fwrite(data, 1, size, stdout); 126b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes } 127b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes} 128b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes 129b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughesvoid LinePrinter::PrintOnNewLine(const string& to_print) { 130b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes if (console_locked_ && !line_buffer_.empty()) { 131b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes output_buffer_.append(line_buffer_); 132b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes output_buffer_.append(1, '\n'); 133b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes line_buffer_.clear(); 134b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes } 135b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes if (!have_blank_line_) { 136b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes PrintOrBuffer("\n", 1); 137b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes } 138b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes if (!to_print.empty()) { 139b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes PrintOrBuffer(&to_print[0], to_print.size()); 140b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes } 141b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes have_blank_line_ = to_print.empty() || *to_print.rbegin() == '\n'; 142b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes} 143b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes 144b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughesvoid LinePrinter::SetConsoleLocked(bool locked) { 145b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes if (locked == console_locked_) 146b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes return; 147b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes 148b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes if (locked) 149b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes PrintOnNewLine(""); 150b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes 151b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes console_locked_ = locked; 152b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes 153b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes if (!locked) { 154b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes PrintOnNewLine(output_buffer_); 155b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes if (!line_buffer_.empty()) { 156b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes Print(line_buffer_, line_type_); 157b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes } 158b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes output_buffer_.clear(); 159b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes line_buffer_.clear(); 160b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes } 161b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes} 162