From 9867754d0826922da6385c4a9ebcf3287a2cedc9 Mon Sep 17 00:00:00 2001 From: Wunkolo Date: Thu, 15 Oct 2020 13:08:59 -0700 Subject: [PATCH] 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. --- src/printer.c | 187 +++++++++++++++++++++++++++----------------------- 1 file changed, 100 insertions(+), 87 deletions(-) diff --git a/src/printer.c b/src/printer.c index babf6b8..783bee8 100644 --- a/src/printer.c +++ b/src/printer.c @@ -9,6 +9,11 @@ #include "cpuid.h" #include "uarch.h" +#ifdef _WIN32 +#define NOMINMAX +#include +#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;nart[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;nart[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; }