Home | History | Annotate | Download | only in gn
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "tools/gn/standard_out.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/command_line.h"
     10 #include "base/logging.h"
     11 #include "base/strings/string_split.h"
     12 #include "build/build_config.h"
     13 
     14 #if defined(OS_WIN)
     15 #include <windows.h>
     16 #else
     17 #include <stdio.h>
     18 #include <unistd.h>
     19 #endif
     20 
     21 namespace {
     22 
     23 bool initialized = false;
     24 
     25 static const char kSwitchColor[] = "color";
     26 static const char kSwitchNoColor[] = "nocolor";
     27 
     28 #if defined(OS_WIN)
     29 HANDLE hstdout;
     30 WORD default_attributes;
     31 #endif
     32 bool is_console = false;
     33 
     34 void EnsureInitialized() {
     35   if (initialized)
     36     return;
     37   initialized = true;
     38 
     39   const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
     40   if (cmdline->HasSwitch(kSwitchNoColor)) {
     41     // Force color off.
     42     is_console = false;
     43     return;
     44   }
     45 
     46 #if defined(OS_WIN)
     47   // On Windows, we can't force the color on. If the output handle isn't a
     48   // console, there's nothing we can do about it.
     49   hstdout = ::GetStdHandle(STD_OUTPUT_HANDLE);
     50   CONSOLE_SCREEN_BUFFER_INFO info;
     51   is_console = !!::GetConsoleScreenBufferInfo(hstdout, &info);
     52   default_attributes = info.wAttributes;
     53 #else
     54   if (cmdline->HasSwitch(kSwitchColor))
     55     is_console = true;
     56   else
     57     is_console = isatty(fileno(stdout));
     58 #endif
     59 }
     60 
     61 void WriteToStdOut(const std::string& output) {
     62   size_t written_bytes = fwrite(output.data(), 1, output.size(), stdout);
     63   DCHECK_EQ(output.size(), written_bytes);
     64 }
     65 
     66 }  // namespace
     67 
     68 #if defined(OS_WIN)
     69 
     70 void OutputString(const std::string& output, TextDecoration dec) {
     71   EnsureInitialized();
     72   if (is_console) {
     73     switch (dec) {
     74       case DECORATION_NONE:
     75         break;
     76       case DECORATION_DIM:
     77         ::SetConsoleTextAttribute(hstdout, FOREGROUND_INTENSITY);
     78         break;
     79       case DECORATION_RED:
     80         ::SetConsoleTextAttribute(hstdout,
     81                                   FOREGROUND_RED | FOREGROUND_INTENSITY);
     82         break;
     83       case DECORATION_GREEN:
     84         // Keep green non-bold.
     85         ::SetConsoleTextAttribute(hstdout, FOREGROUND_GREEN);
     86         break;
     87       case DECORATION_BLUE:
     88         ::SetConsoleTextAttribute(hstdout,
     89                                   FOREGROUND_BLUE | FOREGROUND_INTENSITY);
     90         break;
     91       case DECORATION_YELLOW:
     92         ::SetConsoleTextAttribute(hstdout,
     93                                   FOREGROUND_RED | FOREGROUND_GREEN);
     94         break;
     95     }
     96   }
     97 
     98   DWORD written = 0;
     99   ::WriteFile(hstdout, output.c_str(), static_cast<DWORD>(output.size()),
    100               &written, NULL);
    101 
    102   if (is_console)
    103     ::SetConsoleTextAttribute(hstdout, default_attributes);
    104 }
    105 
    106 #else
    107 
    108 void OutputString(const std::string& output, TextDecoration dec) {
    109   EnsureInitialized();
    110   if (is_console) {
    111     switch (dec) {
    112       case DECORATION_NONE:
    113         break;
    114       case DECORATION_DIM:
    115         WriteToStdOut("\e[2m");
    116         break;
    117       case DECORATION_RED:
    118         WriteToStdOut("\e[31m\e[1m");
    119         break;
    120       case DECORATION_GREEN:
    121         WriteToStdOut("\e[32m");
    122         break;
    123       case DECORATION_BLUE:
    124         WriteToStdOut("\e[34m\e[1m");
    125         break;
    126       case DECORATION_YELLOW:
    127         WriteToStdOut("\e[33m\e[1m");
    128         break;
    129     }
    130   }
    131 
    132   WriteToStdOut(output.data());
    133 
    134   if (is_console && dec != DECORATION_NONE)
    135     WriteToStdOut("\e[0m");
    136 }
    137 
    138 #endif
    139 
    140 void PrintShortHelp(const std::string& line) {
    141   size_t colon_offset = line.find(':');
    142   size_t first_normal = 0;
    143   if (colon_offset != std::string::npos) {
    144     OutputString("  " + line.substr(0, colon_offset), DECORATION_YELLOW);
    145     first_normal = colon_offset;
    146   }
    147 
    148   // See if the colon is followed by a " [" and if so, dim the contents of [ ].
    149   if (first_normal > 0 &&
    150       line.size() > first_normal + 2 &&
    151       line[first_normal + 1] == ' ' && line[first_normal + 2] == '[') {
    152     size_t begin_bracket = first_normal + 2;
    153     OutputString(": ");
    154     first_normal = line.find(']', begin_bracket);
    155     if (first_normal == std::string::npos)
    156       first_normal = line.size();
    157     else
    158       first_normal++;
    159     OutputString(line.substr(begin_bracket, first_normal - begin_bracket),
    160                  DECORATION_DIM);
    161   }
    162 
    163   OutputString(line.substr(first_normal) + "\n");
    164 }
    165 
    166 void PrintLongHelp(const std::string& text) {
    167   std::vector<std::string> lines;
    168   base::SplitStringDontTrim(text, '\n', &lines);
    169 
    170   for (size_t i = 0; i < lines.size(); i++) {
    171     const std::string& line = lines[i];
    172 
    173     // Check for a heading line.
    174     if (!line.empty() && line[0] != ' ') {
    175       // Highlight up to the colon (if any).
    176       size_t chars_to_highlight = line.find(':');
    177       if (chars_to_highlight == std::string::npos)
    178         chars_to_highlight = line.size();
    179       OutputString(line.substr(0, chars_to_highlight), DECORATION_YELLOW);
    180       OutputString(line.substr(chars_to_highlight) + "\n");
    181       continue;
    182     }
    183 
    184     // Check for a comment.
    185     TextDecoration dec = DECORATION_NONE;
    186     for (size_t char_i = 0; char_i < line.size(); char_i++) {
    187       if (line[char_i] == '#') {
    188         // Got a comment, draw dimmed.
    189         dec = DECORATION_DIM;
    190         break;
    191       } else if (line[char_i] != ' ') {
    192         break;
    193       }
    194     }
    195 
    196     OutputString(line + "\n", dec);
    197   }
    198 }
    199 
    200