std::string statusLinePrefix()

in lib/Commands/NinjaBuildCommand.cpp [757:898]


  std::string statusLinePrefix(const std::string& format) const {
    auto begin = format.begin();
    auto end = format.end();

    std::string s;
    s.reserve(format.size() * 4);

    for (auto it = begin; it != end; it++) {
      char c = *it;
      if (c == '%') {
        if (++it == end) {
          s += c;
          break;
        }
        c = *it;
        switch (c) {
        case 'e':
          // Elapsed time.
          {
            auto now = std::chrono::steady_clock::now();
            auto elapsed = now - buildStartTime;
            auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count();
            char buf[64];
            snprintf(buf, sizeof(buf), "%.3f", (double)elapsedMs / 1000.0);
            s.append(buf);
          }
          break;
        case 'f':
          // Number completed.
          s.append(std::to_string(numOutputDescriptions));;
          break;
        case 'o': case 'c':
          // Undifferentiated task completion rate.
          {
            auto now = std::chrono::steady_clock::now();
            auto elapsed = now - buildStartTime;
            auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count();
            double rate = 1000.0 * (double)(numOutputDescriptions) / elapsedMs;
            char buf[64];
            snprintf(buf, sizeof(buf), "%.1f", rate);
            s.append(buf);
          }
          break;
        case 'p':
          // Percentage completed.
          {
            long percentage_started = 100 * numOutputDescriptions / getNumPossibleMaxCommands();
            char buf[64];
            snprintf(buf, sizeof(buf), "%3ld%%", percentage_started);
            s.append(buf);
          }
          break;
        case 'r':
          // Number of edges running.
          {
            auto running = numCommandsScanning + 0;
            s.append(std::to_string(running));
          }
          break;
        case 's':
          // Number of edges started.
          s.append(std::to_string(numCommandsScanning));
          break;
        case 't':
          // Estimated number of edges.
          s.append(std::to_string(getNumPossibleMaxCommands()));
          break;
        case 'u':
          // Remaining number of edges.
          {
            auto remaining = getNumPossibleMaxCommands() - numOutputDescriptions;
            s.append(std::to_string(remaining));
          }
          break;
        case '%':
          s += '%';
          break;
        default:
          s += '%';
          s += c;
          break;
        }
      } else if (c == '\\') {
        if (++it == end) {
          s += c;
          break;
        }
        c = *it;
        switch (c) {
        case 'a': s += '\a'; break;
        case 'b': s += '\b'; break;
        case 'e': s += '\e'; break;
        case 'f': s += '\f'; break;
        case 'n': s += '\n'; break;
        case 'r': s += '\r'; break;
        case 't': s += '\t'; break;
        case 'v': s += '\v'; break;
        case '\\': s += '\\'; break;
        case '0':
          {
            uint8_t result = 0;
            // The '\0033' and '\033' sequences should yield the same result.
            // The first one is canonical, the second one is a fallback.
            // For example, try:
            //  > echo -en '\0033[32mgreen\033[31mred\x1b[0m'
            if (end - it >= 4 && StringRef(&(*(it + 1)), 3).getAsInteger(8, result) == false) {
              it += 3;
              s += result;
            } else if (end - it >= 3 && StringRef(&(*it), 3).getAsInteger(8, result) == false) {
              it += 2;
              s += result;
            } else {
              s += '\\';
              s += c;
            }
          }
          break;
        case 'x':
          {
            uint8_t result = 0;
            if (end - it >= 3 && StringRef(&(*(it + 1)), 2).getAsInteger(16, result) == false) {
              s += result;
              it += 2;
            } else {
              s += '\\';
              s += c;
            }
          }
          break;
        default:
          s += '\\';
          s += c;
          break;
        }
      } else {
        // Not '%' or '\\'
        s += c;
        continue;
      }
    }
    return s;
  }