1
0
mirror of https://github.com/git/git.git synced 2024-09-30 18:22:42 +02:00
git/compat/winansi.c
Johannes Schindelin 492f70913e Work around a regression in Windows 7, causing erase_in_line() to crash sometimes
The function FillConsoleOutputCharacterA() was pretty content in XP to take a NULL
pointer if we did not want to store the number of written columns.  In Windows 7,
it crashes, but only when called from within Git Bash, not from within cmd.exe.
Go figure.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-06-01 00:08:54 -07:00

359 lines
6.9 KiB
C

/*
* Copyright 2008 Peter Harris <git@peter.is-a-geek.org>
*/
#include <windows.h>
#include "../git-compat-util.h"
/*
Functions to be wrapped:
*/
#undef printf
#undef fprintf
#undef fputs
/* TODO: write */
/*
ANSI codes used by git: m, K
This file is git-specific. Therefore, this file does not attempt
to implement any codes that are not used by git.
*/
static HANDLE console;
static WORD plain_attr;
static WORD attr;
static int negative;
static void init(void)
{
CONSOLE_SCREEN_BUFFER_INFO sbi;
static int initialized = 0;
if (initialized)
return;
console = GetStdHandle(STD_OUTPUT_HANDLE);
if (console == INVALID_HANDLE_VALUE)
console = NULL;
if (!console)
return;
GetConsoleScreenBufferInfo(console, &sbi);
attr = plain_attr = sbi.wAttributes;
negative = 0;
initialized = 1;
}
#define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
#define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
static void set_console_attr(void)
{
WORD attributes = attr;
if (negative) {
attributes &= ~FOREGROUND_ALL;
attributes &= ~BACKGROUND_ALL;
/* This could probably use a bitmask
instead of a series of ifs */
if (attr & FOREGROUND_RED)
attributes |= BACKGROUND_RED;
if (attr & FOREGROUND_GREEN)
attributes |= BACKGROUND_GREEN;
if (attr & FOREGROUND_BLUE)
attributes |= BACKGROUND_BLUE;
if (attr & BACKGROUND_RED)
attributes |= FOREGROUND_RED;
if (attr & BACKGROUND_GREEN)
attributes |= FOREGROUND_GREEN;
if (attr & BACKGROUND_BLUE)
attributes |= FOREGROUND_BLUE;
}
SetConsoleTextAttribute(console, attributes);
}
static void erase_in_line(void)
{
CONSOLE_SCREEN_BUFFER_INFO sbi;
DWORD dummy; /* Needed for Windows 7 (or Vista) regression */
if (!console)
return;
GetConsoleScreenBufferInfo(console, &sbi);
FillConsoleOutputCharacterA(console, ' ',
sbi.dwSize.X - sbi.dwCursorPosition.X, sbi.dwCursorPosition,
&dummy);
}
static const char *set_attr(const char *str)
{
const char *func;
size_t len = strspn(str, "0123456789;");
func = str + len;
switch (*func) {
case 'm':
do {
long val = strtol(str, (char **)&str, 10);
switch (val) {
case 0: /* reset */
attr = plain_attr;
negative = 0;
break;
case 1: /* bold */
attr |= FOREGROUND_INTENSITY;
break;
case 2: /* faint */
case 22: /* normal */
attr &= ~FOREGROUND_INTENSITY;
break;
case 3: /* italic */
/* Unsupported */
break;
case 4: /* underline */
case 21: /* double underline */
/* Wikipedia says this flag does nothing */
/* Furthermore, mingw doesn't define this flag
attr |= COMMON_LVB_UNDERSCORE; */
break;
case 24: /* no underline */
/* attr &= ~COMMON_LVB_UNDERSCORE; */
break;
case 5: /* slow blink */
case 6: /* fast blink */
/* We don't have blink, but we do have
background intensity */
attr |= BACKGROUND_INTENSITY;
break;
case 25: /* no blink */
attr &= ~BACKGROUND_INTENSITY;
break;
case 7: /* negative */
negative = 1;
break;
case 27: /* positive */
negative = 0;
break;
case 8: /* conceal */
case 28: /* reveal */
/* Unsupported */
break;
case 30: /* Black */
attr &= ~FOREGROUND_ALL;
break;
case 31: /* Red */
attr &= ~FOREGROUND_ALL;
attr |= FOREGROUND_RED;
break;
case 32: /* Green */
attr &= ~FOREGROUND_ALL;
attr |= FOREGROUND_GREEN;
break;
case 33: /* Yellow */
attr &= ~FOREGROUND_ALL;
attr |= FOREGROUND_RED | FOREGROUND_GREEN;
break;
case 34: /* Blue */
attr &= ~FOREGROUND_ALL;
attr |= FOREGROUND_BLUE;
break;
case 35: /* Magenta */
attr &= ~FOREGROUND_ALL;
attr |= FOREGROUND_RED | FOREGROUND_BLUE;
break;
case 36: /* Cyan */
attr &= ~FOREGROUND_ALL;
attr |= FOREGROUND_GREEN | FOREGROUND_BLUE;
break;
case 37: /* White */
attr |= FOREGROUND_RED |
FOREGROUND_GREEN |
FOREGROUND_BLUE;
break;
case 38: /* Unknown */
break;
case 39: /* reset */
attr &= ~FOREGROUND_ALL;
attr |= (plain_attr & FOREGROUND_ALL);
break;
case 40: /* Black */
attr &= ~BACKGROUND_ALL;
break;
case 41: /* Red */
attr &= ~BACKGROUND_ALL;
attr |= BACKGROUND_RED;
break;
case 42: /* Green */
attr &= ~BACKGROUND_ALL;
attr |= BACKGROUND_GREEN;
break;
case 43: /* Yellow */
attr &= ~BACKGROUND_ALL;
attr |= BACKGROUND_RED | BACKGROUND_GREEN;
break;
case 44: /* Blue */
attr &= ~BACKGROUND_ALL;
attr |= BACKGROUND_BLUE;
break;
case 45: /* Magenta */
attr &= ~BACKGROUND_ALL;
attr |= BACKGROUND_RED | BACKGROUND_BLUE;
break;
case 46: /* Cyan */
attr &= ~BACKGROUND_ALL;
attr |= BACKGROUND_GREEN | BACKGROUND_BLUE;
break;
case 47: /* White */
attr |= BACKGROUND_RED |
BACKGROUND_GREEN |
BACKGROUND_BLUE;
break;
case 48: /* Unknown */
break;
case 49: /* reset */
attr &= ~BACKGROUND_ALL;
attr |= (plain_attr & BACKGROUND_ALL);
break;
default:
/* Unsupported code */
break;
}
str++;
} while (*(str-1) == ';');
set_console_attr();
break;
case 'K':
erase_in_line();
break;
default:
/* Unsupported code */
break;
}
return func + 1;
}
static int ansi_emulate(const char *str, FILE *stream)
{
int rv = 0;
const char *pos = str;
while (*pos) {
pos = strstr(str, "\033[");
if (pos) {
size_t len = pos - str;
if (len) {
size_t out_len = fwrite(str, 1, len, stream);
rv += out_len;
if (out_len < len)
return rv;
}
str = pos + 2;
rv += 2;
fflush(stream);
pos = set_attr(str);
rv += pos - str;
str = pos;
} else {
rv += strlen(str);
fputs(str, stream);
return rv;
}
}
return rv;
}
int winansi_fputs(const char *str, FILE *stream)
{
int rv;
if (!isatty(fileno(stream)))
return fputs(str, stream);
init();
if (!console)
return fputs(str, stream);
rv = ansi_emulate(str, stream);
if (rv >= 0)
return 0;
else
return EOF;
}
static int winansi_vfprintf(FILE *stream, const char *format, va_list list)
{
int len, rv;
char small_buf[256];
char *buf = small_buf;
va_list cp;
if (!isatty(fileno(stream)))
goto abort;
init();
if (!console)
goto abort;
va_copy(cp, list);
len = vsnprintf(small_buf, sizeof(small_buf), format, cp);
va_end(cp);
if (len > sizeof(small_buf) - 1) {
buf = malloc(len + 1);
if (!buf)
goto abort;
len = vsnprintf(buf, len + 1, format, list);
}
rv = ansi_emulate(buf, stream);
if (buf != small_buf)
free(buf);
return rv;
abort:
rv = vfprintf(stream, format, list);
return rv;
}
int winansi_fprintf(FILE *stream, const char *format, ...)
{
va_list list;
int rv;
va_start(list, format);
rv = winansi_vfprintf(stream, format, list);
va_end(list);
return rv;
}
int winansi_printf(const char *format, ...)
{
va_list list;
int rv;
va_start(list, format);
rv = winansi_vfprintf(stdout, format, list);
va_end(list);
return rv;
}