Implement VT100 escape-code detection for Windows

Latest versions of windows have support for the parsing VT100 escape
code sequences, allowing for terminal colors similar to Linux.

https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#screen-colors

Here I have it get the console mode, set the
`ENABLE_VIRTUAL_TERMINAL_PROCESSING` flag, and then grab the console
mode again to both verify that VT100 escape sequences are supported and
that it is enabled after setting it to determine if the printer should
allow for fancy-color mode.
This commit is contained in:
Wunkolo
2020-10-15 13:08:59 -07:00
committed by Wunkolo
parent 5119ece0dd
commit 9867754d08

View File

@@ -9,6 +9,11 @@
#include "cpuid.h"
#include "uarch.h"
#ifdef _WIN32
#define NOMINMAX
#include <Windows.h>
#endif
#define COL_NONE ""
#define COL_INTEL_FANCY_1 "\x1b[46;1m"
#define COL_INTEL_FANCY_2 "\x1b[47;1m"
@@ -42,40 +47,40 @@ enum {
ATTRIBUTE_PEAK
};
static const char* ATTRIBUTE_FIELDS [] = {
"Name:",
static const char* ATTRIBUTE_FIELDS [] = {
"Name:",
"Hypervisor:",
"Microarchitecture:",
"Technology:",
"Max Frequency:",
"Max Frequency:",
"Sockets:",
"Cores:",
"Cores (Total):",
"Cores:",
"Cores (Total):",
"AVX:",
"FMA:",
"L1i Size:",
"L1d Size:",
"L2 Size:",
"FMA:",
"L1i Size:",
"L1d Size:",
"L2 Size:",
"L3 Size:",
"Peak Performance:",
"Peak Performance:",
};
static const int ATTRIBUTE_LIST[] = {
ATTRIBUTE_NAME,
ATTRIBUTE_HYPERVISOR,
ATTRIBUTE_UARCH,
static const int ATTRIBUTE_LIST[] = {
ATTRIBUTE_NAME,
ATTRIBUTE_HYPERVISOR,
ATTRIBUTE_UARCH,
ATTRIBUTE_TECHNOLOGY,
ATTRIBUTE_FREQUENCY,
ATTRIBUTE_FREQUENCY,
ATTRIBUTE_SOCKETS,
ATTRIBUTE_NCORES,
ATTRIBUTE_NCORES_DUAL,
ATTRIBUTE_NCORES,
ATTRIBUTE_NCORES_DUAL,
ATTRIBUTE_AVX,
ATTRIBUTE_FMA,
ATTRIBUTE_L1i,
ATTRIBUTE_L1d,
ATTRIBUTE_L2,
ATTRIBUTE_FMA,
ATTRIBUTE_L1i,
ATTRIBUTE_L1d,
ATTRIBUTE_L2,
ATTRIBUTE_L3,
ATTRIBUTE_PEAK
ATTRIBUTE_PEAK
};
struct ascii {
@@ -94,7 +99,7 @@ struct ascii {
};
void setAttribute(struct ascii* art, int type, char* value) {
art->attributes[type] = value;
art->attributes[type] = value;
art->n_attributes_set++;
}
@@ -109,7 +114,7 @@ char* rgb_to_ansi(struct color* c, bool background, bool bold) {
else
snprintf(str, 44, "\x1b[38;2;%.3d;%.3d;%.3dm", c->R, c->G, c->B);
}
return str;
}
@@ -118,15 +123,15 @@ struct ascii* set_ascii(VENDOR cpuVendor, STYLE style, struct colors* cs) {
uint32_t max_attributes = sizeof(ATTRIBUTE_LIST) / sizeof(ATTRIBUTE_LIST[0]);
for(uint32_t i=0; i < max_attributes; i++) {
if(ATTRIBUTE_FIELDS[i] == NULL) {
printBug("Attribute field at position %d is empty", i);
printBug("Attribute field at position %d is empty", i);
return NULL;
}
if(i > 0 && ATTRIBUTE_LIST[i] == 0) {
printBug("Attribute list at position %d is empty", i);
printBug("Attribute list at position %d is empty", i);
return NULL;
}
}
char *COL_FANCY_1, *COL_FANCY_2, *COL_FANCY_3, *COL_FANCY_4, *COL_RETRO_1, *COL_RETRO_2, *COL_RETRO_3, *COL_RETRO_4;
struct ascii* art = malloc(sizeof(struct ascii));
art->n_attributes_set = 0;
@@ -136,16 +141,16 @@ struct ascii* set_ascii(VENDOR cpuVendor, STYLE style, struct colors* cs) {
for(uint32_t i=0; i < art->max_attributes; i++)
art->attributes[i] = NULL;
strcpy(art->reset,RESET);
if(art->vendor == CPU_VENDOR_INTEL) {
COL_FANCY_1 = COL_INTEL_FANCY_1;
COL_FANCY_2 = COL_INTEL_FANCY_2;
COL_FANCY_3 = COL_INTEL_FANCY_3;
COL_FANCY_4 = COL_INTEL_FANCY_4;
COL_RETRO_1 = COL_INTEL_RETRO_1;
COL_RETRO_2 = COL_INTEL_RETRO_2;
COL_RETRO_3 = COL_INTEL_RETRO_1;
COL_RETRO_4 = COL_INTEL_RETRO_2;
COL_RETRO_2 = COL_INTEL_RETRO_2;
COL_RETRO_3 = COL_INTEL_RETRO_1;
COL_RETRO_4 = COL_INTEL_RETRO_2;
art->ascii_chars[0] = '#';
}
else {
@@ -154,30 +159,38 @@ struct ascii* set_ascii(VENDOR cpuVendor, STYLE style, struct colors* cs) {
COL_FANCY_3 = COL_AMD_FANCY_3;
COL_FANCY_4 = COL_AMD_FANCY_4;
COL_RETRO_1 = COL_AMD_RETRO_1;
COL_RETRO_2 = COL_AMD_RETRO_2;
COL_RETRO_2 = COL_AMD_RETRO_2;
COL_RETRO_3 = COL_AMD_RETRO_1;
COL_RETRO_4 = COL_AMD_RETRO_2;
art->ascii_chars[0] = '@';
COL_RETRO_4 = COL_AMD_RETRO_2;
art->ascii_chars[0] = '@';
}
art->ascii_chars[1] = '#';
if(style == STYLE_EMPTY) {
#ifdef _WIN32
art->style = STYLE_LEGACY;
HANDLE std_handle = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD console_mode;
// Attempt to enable the VT100-processing flag
GetConsoleMode(std_handle, &console_mode);
SetConsoleMode(std_handle, console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
// Get the console mode flag again, to see if it successfully enabled it
GetConsoleMode(std_handle, &console_mode);
// Enable fancy mode if VT100-processing is enabled
art->style = (console_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) ? STYLE_FANCY : STYLE_LEGACY;
#else
art->style = STYLE_FANCY;
#endif
#endif
}
else {
art->style = style;
art->style = style;
}
switch(art->style) {
case STYLE_LEGACY:
strcpy(art->color1_ascii,COL_NONE);
strcpy(art->color2_ascii,COL_NONE);
strcpy(art->color1_text,COL_NONE);
strcpy(art->color2_text,COL_NONE);
strcpy(art->color2_ascii,COL_NONE);
strcpy(art->color1_text,COL_NONE);
strcpy(art->color2_text,COL_NONE);
art->reset[0] = '\0';
break;
case STYLE_FANCY:
@@ -185,14 +198,14 @@ struct ascii* set_ascii(VENDOR cpuVendor, STYLE style, struct colors* cs) {
COL_FANCY_1 = rgb_to_ansi(cs->c1, true, true);
COL_FANCY_2 = rgb_to_ansi(cs->c2, true, true);
COL_FANCY_3 = rgb_to_ansi(cs->c3, false, true);
COL_FANCY_4 = rgb_to_ansi(cs->c4, false, true);
}
COL_FANCY_4 = rgb_to_ansi(cs->c4, false, true);
}
art->ascii_chars[0] = ' ';
art->ascii_chars[1] = ' ';
strcpy(art->color1_ascii,COL_FANCY_1);
strcpy(art->color2_ascii,COL_FANCY_2);
strcpy(art->color1_text,COL_FANCY_3);
strcpy(art->color2_text,COL_FANCY_4);
strcpy(art->color2_ascii,COL_FANCY_2);
strcpy(art->color1_text,COL_FANCY_3);
strcpy(art->color2_text,COL_FANCY_4);
if(cs != NULL) {
free(COL_FANCY_1);
free(COL_FANCY_2);
@@ -200,17 +213,17 @@ struct ascii* set_ascii(VENDOR cpuVendor, STYLE style, struct colors* cs) {
free(COL_FANCY_4);
}
break;
case STYLE_RETRO:
case STYLE_RETRO:
if(cs != NULL) {
COL_RETRO_1 = rgb_to_ansi(cs->c1, false, true);
COL_RETRO_2 = rgb_to_ansi(cs->c2, false, true);
COL_RETRO_2 = rgb_to_ansi(cs->c2, false, true);
COL_RETRO_3 = rgb_to_ansi(cs->c3, false, true);
COL_RETRO_4 = rgb_to_ansi(cs->c4, false, true);
}
COL_RETRO_4 = rgb_to_ansi(cs->c4, false, true);
}
strcpy(art->color1_ascii,COL_RETRO_1);
strcpy(art->color2_ascii,COL_RETRO_2);
strcpy(art->color1_text,COL_RETRO_3);
strcpy(art->color2_text,COL_RETRO_4);
strcpy(art->color2_ascii,COL_RETRO_2);
strcpy(art->color1_text,COL_RETRO_3);
strcpy(art->color2_text,COL_RETRO_4);
if(cs != NULL) {
free(COL_RETRO_1);
free(COL_RETRO_2);
@@ -218,21 +231,21 @@ struct ascii* set_ascii(VENDOR cpuVendor, STYLE style, struct colors* cs) {
free(COL_RETRO_4);
}
break;
case STYLE_INVALID:
case STYLE_INVALID:
default:
printBug("Found invalid style (%d)", art->style);
return NULL;
return NULL;
}
char tmp[NUMBER_OF_LINES*LINE_SIZE];
if(art->vendor == CPU_VENDOR_INTEL)
strcpy(tmp, INTEL_ASCII);
strcpy(tmp, INTEL_ASCII);
else
strcpy(tmp, AMD_ASCII);
strcpy(tmp, AMD_ASCII);
for(int i=0; i < NUMBER_OF_LINES; i++)
strncpy(art->art[i], tmp + i*LINE_SIZE, LINE_SIZE);
strncpy(art->art[i], tmp + i*LINE_SIZE, LINE_SIZE);
return art;
}
@@ -248,7 +261,7 @@ void print_ascii_intel(struct ascii* art, uint32_t la) {
uint32_t space_right;
uint32_t space_up = (NUMBER_OF_LINES - art->n_attributes_set)/2;
uint32_t space_down = NUMBER_OF_LINES - art->n_attributes_set - space_up;
printf("\n");
for(uint32_t n=0;n<NUMBER_OF_LINES;n++) {
@@ -256,7 +269,7 @@ void print_ascii_intel(struct ascii* art, uint32_t la) {
if(flag) {
if(art->art[n][i] == ' ') {
flag = false;
printf("%s%c%s", art->color2_ascii, art->ascii_chars[1], art->reset);
printf("%s%c%s", art->color2_ascii, art->ascii_chars[1], art->reset);
}
else {
printf("%s%c%s", art->color1_ascii, art->ascii_chars[0], art->reset);
@@ -271,10 +284,10 @@ void print_ascii_intel(struct ascii* art, uint32_t la) {
printf("%c",' ');
}
}
if(n > space_up-1 && n < NUMBER_OF_LINES-space_down) {
if(n > space_up-1 && n < NUMBER_OF_LINES-space_down) {
attr_to_print = get_next_attribute(art, attr_to_print);
space_right = 1 + (la - strlen(ATTRIBUTE_FIELDS[attr_to_print]));
space_right = 1 + (la - strlen(ATTRIBUTE_FIELDS[attr_to_print]));
printf("%s%s%s%*s%s%s%s\n",art->color1_text, ATTRIBUTE_FIELDS[attr_to_print], art->reset, space_right, "", art->color2_text, art->attributes[attr_to_print], art->reset);
}
else printf("\n");
@@ -287,12 +300,12 @@ void print_ascii_amd(struct ascii* art, uint32_t la) {
uint32_t space_right;
uint32_t space_up = (NUMBER_OF_LINES - art->n_attributes_set)/2;
uint32_t space_down = NUMBER_OF_LINES - art->n_attributes_set - space_up;
printf("\n");
for(uint32_t n=0;n<NUMBER_OF_LINES;n++) {
for(int i=0;i<LINE_SIZE;i++) {
if(art->art[n][i] == '@')
printf("%s%c%s", art->color1_ascii, art->ascii_chars[0], art->reset);
printf("%s%c%s", art->color1_ascii, art->ascii_chars[0], art->reset);
else if(art->art[n][i] == '#')
printf("%s%c%s", art->color2_ascii, art->ascii_chars[1], art->reset);
else
@@ -301,7 +314,7 @@ void print_ascii_amd(struct ascii* art, uint32_t la) {
if(n > space_up-1 && n < NUMBER_OF_LINES-space_down) {
attr_to_print = get_next_attribute(art, attr_to_print);
space_right = 1 + (la - strlen(ATTRIBUTE_FIELDS[attr_to_print]));
space_right = 1 + (la - strlen(ATTRIBUTE_FIELDS[attr_to_print]));
printf("%s%s%s%*s%s%s%s\n",art->color1_text, ATTRIBUTE_FIELDS[attr_to_print], art->reset, space_right, "", art->color2_text, art->attributes[attr_to_print], art->reset);
}
else printf("\n");
@@ -313,14 +326,14 @@ void print_ascii_amd(struct ascii* art, uint32_t la) {
uint32_t longest_attribute_length(struct ascii* art) {
uint32_t max = 0;
uint64_t len = 0;
for(uint32_t i=0; i < art->max_attributes; i++) {
if(art->attributes[i] != NULL) {
len = strlen(ATTRIBUTE_FIELDS[i]);
if(len > max) max = len;
}
}
return max;
}
@@ -336,7 +349,7 @@ bool print_cpufetch(struct cpuInfo* cpu, struct cache* cach, struct frequency* f
struct ascii* art = set_ascii(get_cpu_vendor(cpu), s, cs);
if(art == NULL)
return false;
char* cpu_name = get_str_cpu_name(cpu);
char* uarch = get_str_uarch(cpu);
char* manufacturing_process = get_str_process(cpu);
@@ -345,7 +358,7 @@ bool print_cpufetch(struct cpuInfo* cpu, struct cache* cach, struct frequency* f
char* n_cores = get_str_topology(cpu, topo, false);
char* n_cores_dual = get_str_topology(cpu, topo, true);
char* avx = get_str_avx(cpu);
char* fma = get_str_fma(cpu);
char* fma = get_str_fma(cpu);
char* l1i = get_str_l1i(topo->cach);
char* l1d = get_str_l1d(topo->cach);
char* l2 = get_str_l2(topo->cach);
@@ -361,23 +374,23 @@ bool print_cpufetch(struct cpuInfo* cpu, struct cache* cach, struct frequency* f
setAttribute(art,ATTRIBUTE_FMA,fma);
setAttribute(art,ATTRIBUTE_L1i,l1i);
setAttribute(art,ATTRIBUTE_L1d,l1d);
setAttribute(art,ATTRIBUTE_L2,l2);
setAttribute(art,ATTRIBUTE_L2,l2);
setAttribute(art,ATTRIBUTE_PEAK,pp);
uint32_t socket_num = get_nsockets(topo);
if (socket_num > 1) {
if (socket_num > 1) {
setAttribute(art, ATTRIBUTE_SOCKETS, sockets);
setAttribute(art, ATTRIBUTE_NCORES_DUAL, n_cores_dual);
}
if(l3 != NULL) {
setAttribute(art,ATTRIBUTE_L3,l3);
setAttribute(art,ATTRIBUTE_L3,l3);
}
if(art->n_attributes_set > NUMBER_OF_LINES) {
printBug("The number of attributes set is bigger than the max that can be displayed");
return false;
return false;
}
if(cpu->hv->present)
setAttribute(art, ATTRIBUTE_HYPERVISOR, cpu->hv->hv_name);
if(cpu->hv->present)
setAttribute(art, ATTRIBUTE_HYPERVISOR, cpu->hv->hv_name);
print_ascii(art);
@@ -392,16 +405,16 @@ bool print_cpufetch(struct cpuInfo* cpu, struct cache* cach, struct frequency* f
free(l1d);
free(l2);
free(l3);
free(pp);
free(pp);
free(art->attributes);
free(art);
if(cs != NULL) free_colors_struct(cs);
free_cache_struct(cach);
free_topo_struct(topo);
free_freq_struct(freq);
free_cpuinfo_struct(cpu);
free_freq_struct(freq);
free_cpuinfo_struct(cpu);
return true;
}