2 * Copyright 2008 Peter Harris <git@peter.is-a-geek.org>
6 #include "../git-compat-util.h"
12 Functions to be wrapped:
21 ANSI codes used by git: m, K
23 This file is git-specific. Therefore, this file does not attempt
24 to implement any codes that are not used by git.
27 static HANDLE console
;
28 static WORD plain_attr
;
31 static FILE *last_stream
= NULL
;
34 typedef struct _CONSOLE_FONT_INFOEX
{
40 WCHAR FaceName
[LF_FACESIZE
];
41 } CONSOLE_FONT_INFOEX
, *PCONSOLE_FONT_INFOEX
;
44 typedef BOOL (WINAPI
*PGETCURRENTCONSOLEFONTEX
)(HANDLE
, BOOL
,
45 PCONSOLE_FONT_INFOEX
);
47 static void print_font_warning(void)
49 warning("Your console font probably doesn\'t support Unicode. If "
50 "you experience strange characters in the output, consider "
51 "switching to a TrueType font such as Lucida Console!");
54 static void check_truetype_font(void)
56 static int truetype_font_checked
;
58 PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx
;
60 /* don't do this twice */
61 if (truetype_font_checked
)
63 truetype_font_checked
= 1;
65 /* GetCurrentConsoleFontEx is available since Vista */
66 pGetCurrentConsoleFontEx
= (PGETCURRENTCONSOLEFONTEX
) GetProcAddress(
67 GetModuleHandle("kernel32.dll"), "GetCurrentConsoleFontEx");
68 if (pGetCurrentConsoleFontEx
) {
69 CONSOLE_FONT_INFOEX cfi
;
70 cfi
.cbSize
= sizeof(cfi
);
71 if (pGetCurrentConsoleFontEx(console
, 0, &cfi
))
72 fontFamily
= cfi
.FontFamily
;
74 /* pre-Vista: check default console font in registry */
76 if (ERROR_SUCCESS
== RegOpenKeyExA(HKEY_CURRENT_USER
, "Console", 0,
78 DWORD size
= sizeof(fontFamily
);
79 RegQueryValueExA(hkey
, "FontFamily", NULL
, NULL
,
80 (LPVOID
) &fontFamily
, &size
);
85 if (!(fontFamily
& TMPF_TRUETYPE
))
86 atexit(print_font_warning
);
89 static int is_console(FILE *stream
)
91 CONSOLE_SCREEN_BUFFER_INFO sbi
;
94 static int initialized
= 0;
96 /* use cached value if stream hasn't changed */
97 if (stream
== last_stream
)
98 return console
!= NULL
;
100 last_stream
= stream
;
103 /* get OS handle of the stream */
104 hcon
= (HANDLE
) _get_osfhandle(_fileno(stream
));
105 if (hcon
== INVALID_HANDLE_VALUE
)
108 /* check if its a handle to a console output screen buffer */
109 if (!GetConsoleScreenBufferInfo(hcon
, &sbi
))
113 attr
= plain_attr
= sbi
.wAttributes
;
122 static int write_console(const char *str
, size_t len
)
124 /* convert utf-8 to utf-16, write directly to console */
125 int wlen
= MultiByteToWideChar(CP_UTF8
, 0, str
, len
, NULL
, 0);
126 wchar_t *wbuf
= (wchar_t *) alloca(wlen
* sizeof(wchar_t));
127 MultiByteToWideChar(CP_UTF8
, 0, str
, len
, wbuf
, wlen
);
129 WriteConsoleW(console
, wbuf
, wlen
, NULL
, NULL
);
132 * if non-ascii characters are printed, check that the current console
136 check_truetype_font();
138 /* return original (utf-8 encoded) length */
142 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
143 #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
145 static void set_console_attr(void)
147 WORD attributes
= attr
;
149 attributes
&= ~FOREGROUND_ALL
;
150 attributes
&= ~BACKGROUND_ALL
;
152 /* This could probably use a bitmask
153 instead of a series of ifs */
154 if (attr
& FOREGROUND_RED
)
155 attributes
|= BACKGROUND_RED
;
156 if (attr
& FOREGROUND_GREEN
)
157 attributes
|= BACKGROUND_GREEN
;
158 if (attr
& FOREGROUND_BLUE
)
159 attributes
|= BACKGROUND_BLUE
;
161 if (attr
& BACKGROUND_RED
)
162 attributes
|= FOREGROUND_RED
;
163 if (attr
& BACKGROUND_GREEN
)
164 attributes
|= FOREGROUND_GREEN
;
165 if (attr
& BACKGROUND_BLUE
)
166 attributes
|= FOREGROUND_BLUE
;
168 SetConsoleTextAttribute(console
, attributes
);
171 static void erase_in_line(void)
173 CONSOLE_SCREEN_BUFFER_INFO sbi
;
174 DWORD dummy
; /* Needed for Windows 7 (or Vista) regression */
179 GetConsoleScreenBufferInfo(console
, &sbi
);
180 FillConsoleOutputCharacterA(console
, ' ',
181 sbi
.dwSize
.X
- sbi
.dwCursorPosition
.X
, sbi
.dwCursorPosition
,
186 static const char *set_attr(const char *str
)
189 size_t len
= strspn(str
, "0123456789;");
195 long val
= strtol(str
, (char **)&str
, 10);
202 attr
|= FOREGROUND_INTENSITY
;
205 case 22: /* normal */
206 attr
&= ~FOREGROUND_INTENSITY
;
211 case 4: /* underline */
212 case 21: /* double underline */
213 /* Wikipedia says this flag does nothing */
214 /* Furthermore, mingw doesn't define this flag
215 attr |= COMMON_LVB_UNDERSCORE; */
217 case 24: /* no underline */
218 /* attr &= ~COMMON_LVB_UNDERSCORE; */
220 case 5: /* slow blink */
221 case 6: /* fast blink */
222 /* We don't have blink, but we do have
223 background intensity */
224 attr
|= BACKGROUND_INTENSITY
;
226 case 25: /* no blink */
227 attr
&= ~BACKGROUND_INTENSITY
;
229 case 7: /* negative */
232 case 27: /* positive */
235 case 8: /* conceal */
236 case 28: /* reveal */
240 attr
&= ~FOREGROUND_ALL
;
243 attr
&= ~FOREGROUND_ALL
;
244 attr
|= FOREGROUND_RED
;
247 attr
&= ~FOREGROUND_ALL
;
248 attr
|= FOREGROUND_GREEN
;
250 case 33: /* Yellow */
251 attr
&= ~FOREGROUND_ALL
;
252 attr
|= FOREGROUND_RED
| FOREGROUND_GREEN
;
255 attr
&= ~FOREGROUND_ALL
;
256 attr
|= FOREGROUND_BLUE
;
258 case 35: /* Magenta */
259 attr
&= ~FOREGROUND_ALL
;
260 attr
|= FOREGROUND_RED
| FOREGROUND_BLUE
;
263 attr
&= ~FOREGROUND_ALL
;
264 attr
|= FOREGROUND_GREEN
| FOREGROUND_BLUE
;
267 attr
|= FOREGROUND_RED
|
271 case 38: /* Unknown */
274 attr
&= ~FOREGROUND_ALL
;
275 attr
|= (plain_attr
& FOREGROUND_ALL
);
278 attr
&= ~BACKGROUND_ALL
;
281 attr
&= ~BACKGROUND_ALL
;
282 attr
|= BACKGROUND_RED
;
285 attr
&= ~BACKGROUND_ALL
;
286 attr
|= BACKGROUND_GREEN
;
288 case 43: /* Yellow */
289 attr
&= ~BACKGROUND_ALL
;
290 attr
|= BACKGROUND_RED
| BACKGROUND_GREEN
;
293 attr
&= ~BACKGROUND_ALL
;
294 attr
|= BACKGROUND_BLUE
;
296 case 45: /* Magenta */
297 attr
&= ~BACKGROUND_ALL
;
298 attr
|= BACKGROUND_RED
| BACKGROUND_BLUE
;
301 attr
&= ~BACKGROUND_ALL
;
302 attr
|= BACKGROUND_GREEN
| BACKGROUND_BLUE
;
305 attr
|= BACKGROUND_RED
|
309 case 48: /* Unknown */
312 attr
&= ~BACKGROUND_ALL
;
313 attr
|= (plain_attr
& BACKGROUND_ALL
);
316 /* Unsupported code */
320 } while (*(str
-1) == ';');
328 /* Unsupported code */
335 static int ansi_emulate(const char *str
, FILE *stream
)
338 const char *pos
= str
;
343 pos
= strstr(str
, "\033[");
345 size_t len
= pos
- str
;
348 size_t out_len
= write_console(str
, len
);
361 size_t len
= strlen(str
);
362 rv
+= write_console(str
, len
);
369 int winansi_fputs(const char *str
, FILE *stream
)
373 if (!is_console(stream
))
374 return fputs(str
, stream
);
376 rv
= ansi_emulate(str
, stream
);
384 int winansi_vfprintf(FILE *stream
, const char *format
, va_list list
)
388 char *buf
= small_buf
;
391 if (!is_console(stream
))
395 len
= vsnprintf(small_buf
, sizeof(small_buf
), format
, cp
);
398 if (len
> sizeof(small_buf
) - 1) {
399 buf
= malloc(len
+ 1);
403 len
= vsnprintf(buf
, len
+ 1, format
, list
);
406 rv
= ansi_emulate(buf
, stream
);
408 if (buf
!= small_buf
)
413 rv
= vfprintf(stream
, format
, list
);
417 int winansi_fprintf(FILE *stream
, const char *format
, ...)
422 va_start(list
, format
);
423 rv
= winansi_vfprintf(stream
, format
, list
);
429 int winansi_printf(const char *format
, ...)
434 va_start(list
, format
);
435 rv
= winansi_vfprintf(stdout
, format
, list
);