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