2 * Copyright 2008 Peter Harris <git@peter.is-a-geek.org>
5 #include "../git-compat-util.h"
11 Functions to be wrapped:
20 ANSI codes used by git: m, K
22 This file is git-specific. Therefore, this file does not attempt
23 to implement any codes that are not used by git.
26 static HANDLE console
;
27 static WORD plain_attr
;
30 static FILE *last_stream
= NULL
;
31 static int non_ascii_used
= 0;
33 typedef struct _CONSOLE_FONT_INFOEX
{
39 WCHAR FaceName
[LF_FACESIZE
];
40 } CONSOLE_FONT_INFOEX
, *PCONSOLE_FONT_INFOEX
;
42 typedef BOOL (WINAPI
*PGETCURRENTCONSOLEFONTEX
)(HANDLE
, BOOL
,
43 PCONSOLE_FONT_INFOEX
);
45 static void warn_if_raster_font(void)
48 PGETCURRENTCONSOLEFONTEX pGetCurrentConsoleFontEx
;
50 /* don't bother if output was ascii only */
54 /* GetCurrentConsoleFontEx is available since Vista */
55 pGetCurrentConsoleFontEx
= GetProcAddress(GetModuleHandle("kernel32.dll"),
56 "GetCurrentConsoleFontEx");
57 if (pGetCurrentConsoleFontEx
) {
58 CONSOLE_FONT_INFOEX cfi
;
59 cfi
.cbSize
= sizeof(cfi
);
60 if (pGetCurrentConsoleFontEx(console
, 0, &cfi
))
61 fontFamily
= cfi
.FontFamily
;
63 /* pre-Vista: check default console font in registry */
65 if (ERROR_SUCCESS
== RegOpenKeyExA(HKEY_CURRENT_USER
, "Console", 0,
67 DWORD size
= sizeof(fontFamily
);
68 RegQueryValueExA(hkey
, "FontFamily", NULL
, NULL
,
69 (LPVOID
) &fontFamily
, &size
);
74 if (!(fontFamily
& TMPF_TRUETYPE
))
75 warning("Your console font probably doesn\'t support "
76 "Unicode. If you experience strange characters in the output, "
77 "consider switching to a TrueType font such as Lucida Console!");
80 static int is_console(FILE *stream
)
82 CONSOLE_SCREEN_BUFFER_INFO sbi
;
85 static int initialized
= 0;
87 /* use cached value if stream hasn't changed */
88 if (stream
== last_stream
)
89 return console
!= NULL
;
94 /* get OS handle of the stream */
95 hcon
= (HANDLE
) _get_osfhandle(_fileno(stream
));
96 if (hcon
== INVALID_HANDLE_VALUE
)
99 /* check if its a handle to a console output screen buffer */
100 if (!GetConsoleScreenBufferInfo(hcon
, &sbi
))
104 attr
= plain_attr
= sbi
.wAttributes
;
107 /* check console font on exit */
108 atexit(warn_if_raster_font
);
115 static int write_console(const char *str
, size_t len
)
117 /* convert utf-8 to utf-16, write directly to console */
118 int wlen
= MultiByteToWideChar(CP_UTF8
, 0, str
, len
, NULL
, 0);
119 wchar_t *wbuf
= (wchar_t *) alloca(wlen
* sizeof(wchar_t));
120 MultiByteToWideChar(CP_UTF8
, 0, str
, len
, wbuf
, wlen
);
122 WriteConsoleW(console
, wbuf
, wlen
, NULL
, NULL
);
124 /* remember if non-ascii characters are printed */
128 /* return original (utf-8 encoded) length */
132 #define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
133 #define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
135 static void set_console_attr(void)
137 WORD attributes
= attr
;
139 attributes
&= ~FOREGROUND_ALL
;
140 attributes
&= ~BACKGROUND_ALL
;
142 /* This could probably use a bitmask
143 instead of a series of ifs */
144 if (attr
& FOREGROUND_RED
)
145 attributes
|= BACKGROUND_RED
;
146 if (attr
& FOREGROUND_GREEN
)
147 attributes
|= BACKGROUND_GREEN
;
148 if (attr
& FOREGROUND_BLUE
)
149 attributes
|= BACKGROUND_BLUE
;
151 if (attr
& BACKGROUND_RED
)
152 attributes
|= FOREGROUND_RED
;
153 if (attr
& BACKGROUND_GREEN
)
154 attributes
|= FOREGROUND_GREEN
;
155 if (attr
& BACKGROUND_BLUE
)
156 attributes
|= FOREGROUND_BLUE
;
158 SetConsoleTextAttribute(console
, attributes
);
161 static void erase_in_line(void)
163 CONSOLE_SCREEN_BUFFER_INFO sbi
;
164 DWORD dummy
; /* Needed for Windows 7 (or Vista) regression */
169 GetConsoleScreenBufferInfo(console
, &sbi
);
170 FillConsoleOutputCharacterA(console
, ' ',
171 sbi
.dwSize
.X
- sbi
.dwCursorPosition
.X
, sbi
.dwCursorPosition
,
176 static const char *set_attr(const char *str
)
179 size_t len
= strspn(str
, "0123456789;");
185 long val
= strtol(str
, (char **)&str
, 10);
192 attr
|= FOREGROUND_INTENSITY
;
195 case 22: /* normal */
196 attr
&= ~FOREGROUND_INTENSITY
;
201 case 4: /* underline */
202 case 21: /* double underline */
203 /* Wikipedia says this flag does nothing */
204 /* Furthermore, mingw doesn't define this flag
205 attr |= COMMON_LVB_UNDERSCORE; */
207 case 24: /* no underline */
208 /* attr &= ~COMMON_LVB_UNDERSCORE; */
210 case 5: /* slow blink */
211 case 6: /* fast blink */
212 /* We don't have blink, but we do have
213 background intensity */
214 attr
|= BACKGROUND_INTENSITY
;
216 case 25: /* no blink */
217 attr
&= ~BACKGROUND_INTENSITY
;
219 case 7: /* negative */
222 case 27: /* positive */
225 case 8: /* conceal */
226 case 28: /* reveal */
230 attr
&= ~FOREGROUND_ALL
;
233 attr
&= ~FOREGROUND_ALL
;
234 attr
|= FOREGROUND_RED
;
237 attr
&= ~FOREGROUND_ALL
;
238 attr
|= FOREGROUND_GREEN
;
240 case 33: /* Yellow */
241 attr
&= ~FOREGROUND_ALL
;
242 attr
|= FOREGROUND_RED
| FOREGROUND_GREEN
;
245 attr
&= ~FOREGROUND_ALL
;
246 attr
|= FOREGROUND_BLUE
;
248 case 35: /* Magenta */
249 attr
&= ~FOREGROUND_ALL
;
250 attr
|= FOREGROUND_RED
| FOREGROUND_BLUE
;
253 attr
&= ~FOREGROUND_ALL
;
254 attr
|= FOREGROUND_GREEN
| FOREGROUND_BLUE
;
257 attr
|= FOREGROUND_RED
|
261 case 38: /* Unknown */
264 attr
&= ~FOREGROUND_ALL
;
265 attr
|= (plain_attr
& FOREGROUND_ALL
);
268 attr
&= ~BACKGROUND_ALL
;
271 attr
&= ~BACKGROUND_ALL
;
272 attr
|= BACKGROUND_RED
;
275 attr
&= ~BACKGROUND_ALL
;
276 attr
|= BACKGROUND_GREEN
;
278 case 43: /* Yellow */
279 attr
&= ~BACKGROUND_ALL
;
280 attr
|= BACKGROUND_RED
| BACKGROUND_GREEN
;
283 attr
&= ~BACKGROUND_ALL
;
284 attr
|= BACKGROUND_BLUE
;
286 case 45: /* Magenta */
287 attr
&= ~BACKGROUND_ALL
;
288 attr
|= BACKGROUND_RED
| BACKGROUND_BLUE
;
291 attr
&= ~BACKGROUND_ALL
;
292 attr
|= BACKGROUND_GREEN
| BACKGROUND_BLUE
;
295 attr
|= BACKGROUND_RED
|
299 case 48: /* Unknown */
302 attr
&= ~BACKGROUND_ALL
;
303 attr
|= (plain_attr
& BACKGROUND_ALL
);
306 /* Unsupported code */
310 } while (*(str
-1) == ';');
318 /* Unsupported code */
325 static int ansi_emulate(const char *str
, FILE *stream
)
328 const char *pos
= str
;
333 pos
= strstr(str
, "\033[");
335 size_t len
= pos
- str
;
338 size_t out_len
= write_console(str
, len
);
351 size_t len
= strlen(str
);
352 rv
+= write_console(str
, len
);
359 int winansi_fputs(const char *str
, FILE *stream
)
363 if (!is_console(stream
))
364 return fputs(str
, stream
);
366 rv
= ansi_emulate(str
, stream
);
374 int winansi_vfprintf(FILE *stream
, const char *format
, va_list list
)
378 char *buf
= small_buf
;
381 if (!is_console(stream
))
385 len
= vsnprintf(small_buf
, sizeof(small_buf
), format
, cp
);
388 if (len
> sizeof(small_buf
) - 1) {
389 buf
= malloc(len
+ 1);
393 len
= vsnprintf(buf
, len
+ 1, format
, list
);
396 rv
= ansi_emulate(buf
, stream
);
398 if (buf
!= small_buf
)
403 rv
= vfprintf(stream
, format
, list
);
407 int winansi_fprintf(FILE *stream
, const char *format
, ...)
412 va_start(list
, format
);
413 rv
= winansi_vfprintf(stream
, format
, list
);
419 int winansi_printf(const char *format
, ...)
424 va_start(list
, format
);
425 rv
= winansi_vfprintf(stdout
, format
, list
);