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 4677f539ab4918514706f986f77529c17a38650be0Elliott HughesLinePrinter::LinePrinter() : have_blank_line_(true) { 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 6277f539ab4918514706f986f77529c17a38650be0Elliott Hughesstatic void Out(const std::string& s) { 6377f539ab4918514706f986f77529c17a38650be0Elliott Hughes // Avoid printf and C strings, since the actual output might contain null 6477f539ab4918514706f986f77529c17a38650be0Elliott Hughes // bytes like UTF-16 does (yuck). 6577f539ab4918514706f986f77529c17a38650be0Elliott Hughes fwrite(s.data(), 1, s.size(), stdout); 6677f539ab4918514706f986f77529c17a38650be0Elliott Hughes} 6777f539ab4918514706f986f77529c17a38650be0Elliott Hughes 68b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughesvoid LinePrinter::Print(string to_print, LineType type) { 6977f539ab4918514706f986f77529c17a38650be0Elliott Hughes if (!smart_terminal_) { 70d68ad69d1dc8dad9245acb75d827a201e2e282eeElliott Hughes Out(to_print + "\n"); 71b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes return; 72b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes } 73b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes 7477f539ab4918514706f986f77529c17a38650be0Elliott Hughes // Print over previous line, if any. 7577f539ab4918514706f986f77529c17a38650be0Elliott Hughes // On Windows, calling a C library function writing to stdout also handles 7677f539ab4918514706f986f77529c17a38650be0Elliott Hughes // pausing the executable when the "Pause" key or Ctrl-S is pressed. 7777f539ab4918514706f986f77529c17a38650be0Elliott Hughes printf("\r"); 78b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes 7977f539ab4918514706f986f77529c17a38650be0Elliott Hughes if (type == INFO) { 80b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes#ifdef _WIN32 81b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes CONSOLE_SCREEN_BUFFER_INFO csbi; 82b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes GetConsoleScreenBufferInfo(console_, &csbi); 83b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes 84d21dc825bbecad6ce480c5e5c574cc77eadcd779Spencer Low // TODO: std::wstring to_print_wide; if (!android::base::UTF8ToWide(to_print, &to_print_wide)... 85b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // TODO: wstring ElideMiddle. 86b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes to_print = ElideMiddle(to_print, static_cast<size_t>(csbi.dwSize.X)); 87b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // We don't want to have the cursor spamming back and forth, so instead of 88b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // printf use WriteConsoleOutput which updates the contents of the buffer, 89b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // but doesn't move the cursor position. 90b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes COORD buf_size = { csbi.dwSize.X, 1 }; 91b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes COORD zero_zero = { 0, 0 }; 92b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes SMALL_RECT target = { 93b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes csbi.dwCursorPosition.X, csbi.dwCursorPosition.Y, 94b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes static_cast<SHORT>(csbi.dwCursorPosition.X + csbi.dwSize.X - 1), 95b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes csbi.dwCursorPosition.Y 96b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes }; 97b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes vector<CHAR_INFO> char_data(csbi.dwSize.X); 98b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes for (size_t i = 0; i < static_cast<size_t>(csbi.dwSize.X); ++i) { 99b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // TODO: UnicodeChar instead of AsciiChar, to_print_wide[i]. 100b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes char_data[i].Char.AsciiChar = i < to_print.size() ? to_print[i] : ' '; 101b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes char_data[i].Attributes = csbi.wAttributes; 102b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes } 103b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // TODO: WriteConsoleOutputW. 104b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes WriteConsoleOutput(console_, &char_data[0], buf_size, zero_zero, &target); 105b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes#else 106b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // Limit output to width of the terminal if provided so we don't cause 107b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes // line-wrapping. 108b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes winsize size; 109b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes if ((ioctl(0, TIOCGWINSZ, &size) == 0) && size.ws_col) { 110b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes to_print = ElideMiddle(to_print, size.ws_col); 111b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes } 11277f539ab4918514706f986f77529c17a38650be0Elliott Hughes Out(to_print); 113b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes printf("\x1B[K"); // Clear to end of line. 114b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes fflush(stdout); 115b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes#endif 116b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes 117b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes have_blank_line_ = false; 118b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes } else { 11977f539ab4918514706f986f77529c17a38650be0Elliott Hughes Out(to_print); 12077f539ab4918514706f986f77529c17a38650be0Elliott Hughes Out("\n"); 12177f539ab4918514706f986f77529c17a38650be0Elliott Hughes have_blank_line_ = true; 122b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes } 123b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes} 124b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes 12577f539ab4918514706f986f77529c17a38650be0Elliott Hughesvoid LinePrinter::KeepInfoLine() { 12677f539ab4918514706f986f77529c17a38650be0Elliott Hughes if (!have_blank_line_) Out("\n"); 1271a9979ec1ee913157a0e8e570ca93feacf58634eJosh Gao have_blank_line_ = true; 128b708d1628332ea9266d08f0297cd9e9ee341a64fElliott Hughes} 129