]> git.ipfire.org Git - thirdparty/git.git/blame - compat/winansi.c
Merge branch 'gb/maint-am-stgit-author-to-from-fix'
[thirdparty/git.git] / compat / winansi.c
CommitLineData
c09df8a7
PH
1/*
2 * Copyright 2008 Peter Harris <git@peter.is-a-geek.org>
3 */
4
c09df8a7
PH
5#include "../git-compat-util.h"
6
7/*
8 Functions to be wrapped:
9*/
10#undef printf
11#undef fprintf
12#undef fputs
13/* TODO: write */
14
15/*
16 ANSI codes used by git: m, K
17
18 This file is git-specific. Therefore, this file does not attempt
19 to implement any codes that are not used by git.
c09df8a7
PH
20*/
21
22static HANDLE console;
23static WORD plain_attr;
24static WORD attr;
25static int negative;
26
27static void init(void)
28{
29 CONSOLE_SCREEN_BUFFER_INFO sbi;
30
31 static int initialized = 0;
32 if (initialized)
33 return;
34
35 console = GetStdHandle(STD_OUTPUT_HANDLE);
36 if (console == INVALID_HANDLE_VALUE)
37 console = NULL;
38
39 if (!console)
40 return;
41
42 GetConsoleScreenBufferInfo(console, &sbi);
43 attr = plain_attr = sbi.wAttributes;
44 negative = 0;
45
46 initialized = 1;
47}
48
49
50#define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
51#define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
52
53static void set_console_attr(void)
54{
55 WORD attributes = attr;
56 if (negative) {
57 attributes &= ~FOREGROUND_ALL;
58 attributes &= ~BACKGROUND_ALL;
59
60 /* This could probably use a bitmask
61 instead of a series of ifs */
62 if (attr & FOREGROUND_RED)
63 attributes |= BACKGROUND_RED;
64 if (attr & FOREGROUND_GREEN)
65 attributes |= BACKGROUND_GREEN;
66 if (attr & FOREGROUND_BLUE)
67 attributes |= BACKGROUND_BLUE;
68
69 if (attr & BACKGROUND_RED)
70 attributes |= FOREGROUND_RED;
71 if (attr & BACKGROUND_GREEN)
72 attributes |= FOREGROUND_GREEN;
73 if (attr & BACKGROUND_BLUE)
74 attributes |= FOREGROUND_BLUE;
75 }
76 SetConsoleTextAttribute(console, attributes);
77}
78
1897713f
JS
79static void erase_in_line(void)
80{
81 CONSOLE_SCREEN_BUFFER_INFO sbi;
492f7091 82 DWORD dummy; /* Needed for Windows 7 (or Vista) regression */
1897713f
JS
83
84 if (!console)
85 return;
86
87 GetConsoleScreenBufferInfo(console, &sbi);
88 FillConsoleOutputCharacterA(console, ' ',
89 sbi.dwSize.X - sbi.dwCursorPosition.X, sbi.dwCursorPosition,
492f7091 90 &dummy);
1897713f
JS
91}
92
93
c09df8a7
PH
94static const char *set_attr(const char *str)
95{
96 const char *func;
97 size_t len = strspn(str, "0123456789;");
98 func = str + len;
99
100 switch (*func) {
101 case 'm':
102 do {
103 long val = strtol(str, (char **)&str, 10);
104 switch (val) {
105 case 0: /* reset */
106 attr = plain_attr;
107 negative = 0;
108 break;
109 case 1: /* bold */
110 attr |= FOREGROUND_INTENSITY;
111 break;
112 case 2: /* faint */
113 case 22: /* normal */
114 attr &= ~FOREGROUND_INTENSITY;
115 break;
116 case 3: /* italic */
117 /* Unsupported */
118 break;
119 case 4: /* underline */
120 case 21: /* double underline */
121 /* Wikipedia says this flag does nothing */
122 /* Furthermore, mingw doesn't define this flag
123 attr |= COMMON_LVB_UNDERSCORE; */
124 break;
125 case 24: /* no underline */
126 /* attr &= ~COMMON_LVB_UNDERSCORE; */
127 break;
128 case 5: /* slow blink */
129 case 6: /* fast blink */
130 /* We don't have blink, but we do have
131 background intensity */
132 attr |= BACKGROUND_INTENSITY;
133 break;
134 case 25: /* no blink */
135 attr &= ~BACKGROUND_INTENSITY;
136 break;
137 case 7: /* negative */
138 negative = 1;
139 break;
140 case 27: /* positive */
141 negative = 0;
142 break;
143 case 8: /* conceal */
144 case 28: /* reveal */
145 /* Unsupported */
146 break;
147 case 30: /* Black */
148 attr &= ~FOREGROUND_ALL;
149 break;
150 case 31: /* Red */
151 attr &= ~FOREGROUND_ALL;
152 attr |= FOREGROUND_RED;
153 break;
154 case 32: /* Green */
155 attr &= ~FOREGROUND_ALL;
156 attr |= FOREGROUND_GREEN;
157 break;
158 case 33: /* Yellow */
159 attr &= ~FOREGROUND_ALL;
160 attr |= FOREGROUND_RED | FOREGROUND_GREEN;
161 break;
162 case 34: /* Blue */
163 attr &= ~FOREGROUND_ALL;
164 attr |= FOREGROUND_BLUE;
165 break;
166 case 35: /* Magenta */
167 attr &= ~FOREGROUND_ALL;
168 attr |= FOREGROUND_RED | FOREGROUND_BLUE;
169 break;
170 case 36: /* Cyan */
171 attr &= ~FOREGROUND_ALL;
172 attr |= FOREGROUND_GREEN | FOREGROUND_BLUE;
173 break;
174 case 37: /* White */
175 attr |= FOREGROUND_RED |
176 FOREGROUND_GREEN |
177 FOREGROUND_BLUE;
178 break;
179 case 38: /* Unknown */
180 break;
181 case 39: /* reset */
182 attr &= ~FOREGROUND_ALL;
183 attr |= (plain_attr & FOREGROUND_ALL);
184 break;
185 case 40: /* Black */
186 attr &= ~BACKGROUND_ALL;
187 break;
188 case 41: /* Red */
189 attr &= ~BACKGROUND_ALL;
190 attr |= BACKGROUND_RED;
191 break;
192 case 42: /* Green */
193 attr &= ~BACKGROUND_ALL;
194 attr |= BACKGROUND_GREEN;
195 break;
196 case 43: /* Yellow */
197 attr &= ~BACKGROUND_ALL;
198 attr |= BACKGROUND_RED | BACKGROUND_GREEN;
199 break;
200 case 44: /* Blue */
201 attr &= ~BACKGROUND_ALL;
202 attr |= BACKGROUND_BLUE;
203 break;
204 case 45: /* Magenta */
205 attr &= ~BACKGROUND_ALL;
206 attr |= BACKGROUND_RED | BACKGROUND_BLUE;
207 break;
208 case 46: /* Cyan */
209 attr &= ~BACKGROUND_ALL;
210 attr |= BACKGROUND_GREEN | BACKGROUND_BLUE;
211 break;
212 case 47: /* White */
213 attr |= BACKGROUND_RED |
214 BACKGROUND_GREEN |
215 BACKGROUND_BLUE;
216 break;
217 case 48: /* Unknown */
218 break;
219 case 49: /* reset */
220 attr &= ~BACKGROUND_ALL;
221 attr |= (plain_attr & BACKGROUND_ALL);
222 break;
223 default:
224 /* Unsupported code */
225 break;
226 }
227 str++;
228 } while (*(str-1) == ';');
229
230 set_console_attr();
231 break;
232 case 'K':
1897713f 233 erase_in_line();
c09df8a7
PH
234 break;
235 default:
236 /* Unsupported code */
237 break;
238 }
239
240 return func + 1;
241}
242
243static int ansi_emulate(const char *str, FILE *stream)
244{
245 int rv = 0;
246 const char *pos = str;
247
248 while (*pos) {
249 pos = strstr(str, "\033[");
250 if (pos) {
251 size_t len = pos - str;
252
253 if (len) {
254 size_t out_len = fwrite(str, 1, len, stream);
255 rv += out_len;
256 if (out_len < len)
257 return rv;
258 }
259
260 str = pos + 2;
261 rv += 2;
262
263 fflush(stream);
264
265 pos = set_attr(str);
266 rv += pos - str;
267 str = pos;
268 } else {
269 rv += strlen(str);
270 fputs(str, stream);
271 return rv;
272 }
273 }
274 return rv;
275}
276
277int winansi_fputs(const char *str, FILE *stream)
278{
279 int rv;
280
281 if (!isatty(fileno(stream)))
282 return fputs(str, stream);
283
284 init();
285
286 if (!console)
287 return fputs(str, stream);
288
289 rv = ansi_emulate(str, stream);
290
291 if (rv >= 0)
292 return 0;
293 else
294 return EOF;
295}
296
297static int winansi_vfprintf(FILE *stream, const char *format, va_list list)
298{
299 int len, rv;
300 char small_buf[256];
301 char *buf = small_buf;
302 va_list cp;
303
304 if (!isatty(fileno(stream)))
305 goto abort;
306
307 init();
308
309 if (!console)
310 goto abort;
311
312 va_copy(cp, list);
313 len = vsnprintf(small_buf, sizeof(small_buf), format, cp);
314 va_end(cp);
315
316 if (len > sizeof(small_buf) - 1) {
317 buf = malloc(len + 1);
318 if (!buf)
319 goto abort;
320
321 len = vsnprintf(buf, len + 1, format, list);
322 }
323
324 rv = ansi_emulate(buf, stream);
325
326 if (buf != small_buf)
327 free(buf);
328 return rv;
329
330abort:
331 rv = vfprintf(stream, format, list);
332 return rv;
333}
334
335int winansi_fprintf(FILE *stream, const char *format, ...)
336{
337 va_list list;
338 int rv;
339
340 va_start(list, format);
341 rv = winansi_vfprintf(stream, format, list);
342 va_end(list);
343
344 return rv;
345}
346
347int winansi_printf(const char *format, ...)
348{
349 va_list list;
350 int rv;
351
352 va_start(list, format);
353 rv = winansi_vfprintf(stdout, format, list);
354 va_end(list);
355
356 return rv;
357}