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;
}