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
;
32 static int non_ascii_used
= 0;
35 typedef struct _CONSOLE_FONT_INFOEX
{
41 WCHAR FaceName
[LF_FACESIZE
];
42 } CONSOLE_FONT_INFOEX
, *PCONSOLE_FONT_INFOEX
;
45 typedef BOOL (WINAPI
*PGETCURRENTCONSOLEFONTEX
)(HANDLE
, BOOL
,
46 PCONSOLE_FONT_INFOEX
);
48 static void warn_if_raster_font(void)
51 PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx
;
53 /* don't bother if output was ascii only */
57 /* GetCurrentConsoleFontEx is available since Vista */
58 pGetCurrentConsoleFontEx
= (PGETCURRENTCONSOLEFONTEX
) GetProcAddress(
59 GetModuleHandle("kernel32.dll"), "GetCurrentConsoleFontEx");
60 if (pGetCurrentConsoleFontEx
) {
61 CONSOLE_FONT_INFOEX cfi
;
62 cfi
.cbSize
= sizeof(cfi
);
63 if (pGetCurrentConsoleFontEx(console
, 0, &cfi
))
64 fontFamily
= cfi
.FontFamily
;
66 /* pre-Vista: check default console font in registry */
68 if (ERROR_SUCCESS
== RegOpenKeyExA(HKEY_CURRENT_USER
, "Console", 0,
70 DWORD size
= sizeof(fontFamily
);
71 RegQueryValueExA(hkey
, "FontFamily", NULL
, NULL
,
72 (LPVOID
) &fontFamily
, &size
);
77 if (!(fontFamily
& TMPF_TRUETYPE
))
78 warning("Your console font probably doesn\'t support "
79 "Unicode. If you experience strange characters in the output, "
80 "consider switching to a TrueType font such as Lucida Console!");
83 static int is_console(FILE *stream
)
85 CONSOLE_SCREEN_BUFFER_INFO sbi
;
88 static int initialized
= 0;
90 /* use cached value if stream hasn't changed */
91 if (stream
== last_stream
)
92 return console
!= NULL
;
97 /* get OS handle of the stream */
98 hcon
= (HANDLE
) _get_osfhandle(_fileno(stream
));
99 if (hcon
== INVALID_HANDLE_VALUE
)
102 /* check if its a handle to a console output screen buffer */
103 if (!GetConsoleScreenBufferInfo(hcon
, &sbi
))
107 attr
= plain_attr
= sbi
.wAttributes
;
110 /* check console font on exit */
111 atexit(warn_if_raster_font
);
118 static int write_console(const char *str
, size_t len
)
120 /* convert utf-8 to utf-16, write directly to console */
121 int wlen
= MultiByteToWideChar(CP_UTF8
, 0, str
, len
, NULL
, 0);
122 wchar_t *wbuf
= (wchar_t *) alloca(wlen
* sizeof(wchar_t));
123 MultiByteToWideChar(CP_UTF8
, 0, str
, len
, wbuf
, wlen
);
125 WriteConsoleW(console
, wbuf
, wlen
, NULL
, NULL
);
127 /* remember if non-ascii characters are printed */
131 /* return original (utf-8 encoded) length */
135 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
136 #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
138 static void set_console_attr(void)
140 WORD attributes
= attr
;
142 attributes
&= ~FOREGROUND_ALL
;
143 attributes
&= ~BACKGROUND_ALL
;
145 /* This could probably use a bitmask
146 instead of a series of ifs */
147 if (attr
& FOREGROUND_RED
)
148 attributes
|= BACKGROUND_RED
;
149 if (attr
& FOREGROUND_GREEN
)
150 attributes
|= BACKGROUND_GREEN
;
151 if (attr
& FOREGROUND_BLUE
)
152 attributes
|= BACKGROUND_BLUE
;
154 if (attr
& BACKGROUND_RED
)
155 attributes
|= FOREGROUND_RED
;
156 if (attr
& BACKGROUND_GREEN
)
157 attributes
|= FOREGROUND_GREEN
;
158 if (attr
& BACKGROUND_BLUE
)
159 attributes
|= FOREGROUND_BLUE
;
161 SetConsoleTextAttribute(console
, attributes
);
164 static void erase_in_line(void)
166 CONSOLE_SCREEN_BUFFER_INFO sbi
;
167 DWORD dummy
; /* Needed for Windows 7 (or Vista) regression */
172 GetConsoleScreenBufferInfo(console
, &sbi
);
173 FillConsoleOutputCharacterA(console
, ' ',
174 sbi
.dwSize
.X
- sbi
.dwCursorPosition
.X
, sbi
.dwCursorPosition
,
179 static const char *set_attr(const char *str
)
182 size_t len
= strspn(str
, "0123456789;");
188 long val
= strtol(str
, (char **)&str
, 10);
195 attr
|= FOREGROUND_INTENSITY
;
198 case 22: /* normal */
199 attr
&= ~FOREGROUND_INTENSITY
;
204 case 4: /* underline */
205 case 21: /* double underline */
206 /* Wikipedia says this flag does nothing */
207 /* Furthermore, mingw doesn't define this flag
208 attr |= COMMON_LVB_UNDERSCORE; */
210 case 24: /* no underline */
211 /* attr &= ~COMMON_LVB_UNDERSCORE; */
213 case 5: /* slow blink */
214 case 6: /* fast blink */
215 /* We don't have blink, but we do have
216 background intensity */
217 attr
|= BACKGROUND_INTENSITY
;
219 case 25: /* no blink */
220 attr
&= ~BACKGROUND_INTENSITY
;
222 case 7: /* negative */
225 case 27: /* positive */
228 case 8: /* conceal */
229 case 28: /* reveal */
233 attr
&= ~FOREGROUND_ALL
;
236 attr
&= ~FOREGROUND_ALL
;
237 attr
|= FOREGROUND_RED
;
240 attr
&= ~FOREGROUND_ALL
;
241 attr
|= FOREGROUND_GREEN
;
243 case 33: /* Yellow */
244 attr
&= ~FOREGROUND_ALL
;
245 attr
|= FOREGROUND_RED
| FOREGROUND_GREEN
;
248 attr
&= ~FOREGROUND_ALL
;
249 attr
|= FOREGROUND_BLUE
;
251 case 35: /* Magenta */
252 attr
&= ~FOREGROUND_ALL
;
253 attr
|= FOREGROUND_RED
| FOREGROUND_BLUE
;
256 attr
&= ~FOREGROUND_ALL
;
257 attr
|= FOREGROUND_GREEN
| FOREGROUND_BLUE
;
260 attr
|= FOREGROUND_RED
|
264 case 38: /* Unknown */
267 attr
&= ~FOREGROUND_ALL
;
268 attr
|= (plain_attr
& FOREGROUND_ALL
);
271 attr
&= ~BACKGROUND_ALL
;
274 attr
&= ~BACKGROUND_ALL
;
275 attr
|= BACKGROUND_RED
;
278 attr
&= ~BACKGROUND_ALL
;
279 attr
|= BACKGROUND_GREEN
;
281 case 43: /* Yellow */
282 attr
&= ~BACKGROUND_ALL
;
283 attr
|= BACKGROUND_RED
| BACKGROUND_GREEN
;
286 attr
&= ~BACKGROUND_ALL
;
287 attr
|= BACKGROUND_BLUE
;
289 case 45: /* Magenta */
290 attr
&= ~BACKGROUND_ALL
;
291 attr
|= BACKGROUND_RED
| BACKGROUND_BLUE
;
294 attr
&= ~BACKGROUND_ALL
;
295 attr
|= BACKGROUND_GREEN
| BACKGROUND_BLUE
;
298 attr
|= BACKGROUND_RED
|
302 case 48: /* Unknown */
305 attr
&= ~BACKGROUND_ALL
;
306 attr
|= (plain_attr
& BACKGROUND_ALL
);
309 /* Unsupported code */
313 } while (*(str
-1) == ';');
321 /* Unsupported code */
328 static int ansi_emulate(const char *str
, FILE *stream
)
331 const char *pos
= str
;
336 pos
= strstr(str
, "\033[");
338 size_t len
= pos
- str
;
341 size_t out_len
= write_console(str
, len
);
354 size_t len
= strlen(str
);
355 rv
+= write_console(str
, len
);
362 int winansi_fputs(const char *str
, FILE *stream
)
366 if (!is_console(stream
))
367 return fputs(str
, stream
);
369 rv
= ansi_emulate(str
, stream
);
377 int winansi_vfprintf(FILE *stream
, const char *format
, va_list list
)
381 char *buf
= small_buf
;
384 if (!is_console(stream
))
388 len
= vsnprintf(small_buf
, sizeof(small_buf
), format
, cp
);
391 if (len
> sizeof(small_buf
) - 1) {
392 buf
= malloc(len
+ 1);
396 len
= vsnprintf(buf
, len
+ 1, format
, list
);
399 rv
= ansi_emulate(buf
, stream
);
401 if (buf
!= small_buf
)
406 rv
= vfprintf(stream
, format
, list
);
410 int winansi_fprintf(FILE *stream
, const char *format
, ...)
415 va_start(list
, format
);
416 rv
= winansi_vfprintf(stream
, format
, list
);
422 int winansi_printf(const char *format
, ...)
427 va_start(list
, format
);
428 rv
= winansi_vfprintf(stdout
, format
, list
);