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