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