diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2010-06-27 20:42:17 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-06-27 20:42:17 +0200 |
commit | 1a3b0710f5424fd71a7c44eade5d4398c44ae431 (patch) | |
tree | f17e97a838a69d74efa498b5e268c62ae72089af /miscutils/conspy.c | |
parent | 31c3dad85142eac32d441f0f1140eda9884d7774 (diff) | |
download | busybox-w32-1a3b0710f5424fd71a7c44eade5d4398c44ae431.tar.gz busybox-w32-1a3b0710f5424fd71a7c44eade5d4398c44ae431.tar.bz2 busybox-w32-1a3b0710f5424fd71a7c44eade5d4398c44ae431.zip |
conspy: significant output minimization; blink attribute support
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'miscutils/conspy.c')
-rw-r--r-- | miscutils/conspy.c | 198 |
1 files changed, 126 insertions, 72 deletions
diff --git a/miscutils/conspy.c b/miscutils/conspy.c index 11758c603..11105f0b8 100644 --- a/miscutils/conspy.c +++ b/miscutils/conspy.c | |||
@@ -8,10 +8,6 @@ | |||
8 | * http://ace-host.stuart.id.au/russell/files/conspy.c | 8 | * http://ace-host.stuart.id.au/russell/files/conspy.c |
9 | * | 9 | * |
10 | * Licensed under GPLv2 or later, see file License in this tarball for details. | 10 | * Licensed under GPLv2 or later, see file License in this tarball for details. |
11 | * | ||
12 | * example: conspy num shared access to console num | ||
13 | * or conspy -d num screenshot of console num | ||
14 | * or conspy -cs num poor man's GNU screen like | ||
15 | */ | 11 | */ |
16 | 12 | ||
17 | //applet:IF_CONSPY(APPLET(conspy, _BB_DIR_BIN, _BB_SUID_DROP)) | 13 | //applet:IF_CONSPY(APPLET(conspy, _BB_DIR_BIN, _BB_SUID_DROP)) |
@@ -23,12 +19,12 @@ | |||
23 | //config: default n | 19 | //config: default n |
24 | //config: help | 20 | //config: help |
25 | //config: A text-mode VNC like program for Linux virtual terminals. | 21 | //config: A text-mode VNC like program for Linux virtual terminals. |
26 | //config: example : conspy num shared access to console num | 22 | //config: example: conspy NUM shared access to console num |
27 | //config: or conspy -d num screenshot of console num | 23 | //config: or conspy -nd NUM screenshot of console num |
28 | //config: or conspy -cs num poor man's GNU screen like | 24 | //config: or conspy -cs NUM poor man's GNU screen like |
29 | 25 | ||
30 | //usage:#define conspy_trivial_usage | 26 | //usage:#define conspy_trivial_usage |
31 | //usage: "[-vcsndf] [-x ROW] [-y LINE] [CONSOLE_NO]" | 27 | //usage: "[-vcsndf] [-x COL] [-y LINE] [CONSOLE_NO]" |
32 | //usage:#define conspy_full_usage "\n\n" | 28 | //usage:#define conspy_full_usage "\n\n" |
33 | //usage: "A text-mode VNC like program for Linux virtual consoles." | 29 | //usage: "A text-mode VNC like program for Linux virtual consoles." |
34 | //usage: "\nTo exit, quickly press ESC 3 times." | 30 | //usage: "\nTo exit, quickly press ESC 3 times." |
@@ -40,14 +36,14 @@ | |||
40 | //usage: "\n -n Black & white" | 36 | //usage: "\n -n Black & white" |
41 | //usage: "\n -d Dump console to stdout" | 37 | //usage: "\n -d Dump console to stdout" |
42 | //usage: "\n -f Follow cursor" | 38 | //usage: "\n -f Follow cursor" |
43 | //usage: "\n -x ROW Starting row" | 39 | //usage: "\n -x COL Starting column" |
44 | //usage: "\n -y LINE Starting line" | 40 | //usage: "\n -y LINE Starting line" |
45 | 41 | ||
46 | #include "libbb.h" | 42 | #include "libbb.h" |
47 | #include <sys/kd.h> | 43 | #include <sys/kd.h> |
48 | 44 | ||
49 | struct screen_info { | 45 | struct screen_info { |
50 | unsigned char lines, rows, cursor_x, cursor_y; | 46 | unsigned char lines, cols, cursor_x, cursor_y; |
51 | }; | 47 | }; |
52 | 48 | ||
53 | #define CHAR(x) ((uint8_t)((x)[0])) | 49 | #define CHAR(x) ((uint8_t)((x)[0])) |
@@ -62,20 +58,29 @@ struct globals { | |||
62 | int kbd_fd; | 58 | int kbd_fd; |
63 | unsigned width; | 59 | unsigned width; |
64 | unsigned height; | 60 | unsigned height; |
65 | uint8_t last_attr; | 61 | unsigned col; |
62 | unsigned line; | ||
66 | int ioerror_count; | 63 | int ioerror_count; |
67 | int key_count; | 64 | int key_count; |
68 | int escape_count; | 65 | int escape_count; |
69 | int nokeys; | 66 | int nokeys; |
70 | int current; | 67 | int current; |
71 | int vcsa_fd; | 68 | int vcsa_fd; |
72 | struct screen_info info; | 69 | uint16_t last_attr; |
70 | uint8_t last_bold; | ||
71 | uint8_t last_blink; | ||
72 | uint8_t last_fg; | ||
73 | uint8_t last_bg; | ||
74 | char attrbuf[sizeof("\033[0;1;5;30;40m")]; | ||
75 | smallint curoff; | ||
76 | struct screen_info remote; | ||
73 | struct termios term_orig; | 77 | struct termios term_orig; |
74 | }; | 78 | }; |
75 | 79 | ||
76 | #define G (*ptr_to_globals) | 80 | #define G (*ptr_to_globals) |
77 | #define INIT_G() do { \ | 81 | #define INIT_G() do { \ |
78 | SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ | 82 | SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ |
83 | strcpy((char*)&G.last_attr, "\xff\xff\xff\xff\xff\xff" "\033["); \ | ||
79 | } while (0) | 84 | } while (0) |
80 | 85 | ||
81 | enum { | 86 | enum { |
@@ -96,8 +101,8 @@ static void screen_read_close(void) | |||
96 | 101 | ||
97 | xread(G.vcsa_fd, data, G.size); | 102 | xread(G.vcsa_fd, data, G.size); |
98 | G.last_attr = 0; | 103 | G.last_attr = 0; |
99 | for (i = 0; i < G.info.lines; i++) { | 104 | for (i = 0; i < G.remote.lines; i++) { |
100 | for (j = 0; j < G.info.rows; j++, NEXT(data)) { | 105 | for (j = 0; j < G.remote.cols; j++, NEXT(data)) { |
101 | unsigned x = j - G.x; // if will catch j < G.x too | 106 | unsigned x = j - G.x; // if will catch j < G.x too |
102 | unsigned y = i - G.y; // if will catch i < G.y too | 107 | unsigned y = i - G.y; // if will catch i < G.y too |
103 | 108 | ||
@@ -140,51 +145,101 @@ static void screen_char(char *data) | |||
140 | // text 8th bit | 145 | // text 8th bit |
141 | // converting RGB color bit triad to BGR: | 146 | // converting RGB color bit triad to BGR: |
142 | static const char color[8] = "04261537"; | 147 | static const char color[8] = "04261537"; |
148 | char *ptr; | ||
149 | uint8_t fg, bold, bg, blink; | ||
143 | 150 | ||
144 | G.last_attr = attr; | 151 | G.last_attr = attr; |
145 | printf("\033[%c;4%c;3%cm", | 152 | |
146 | (attr & 8) ? '1' : '0', // bold text / reset all | 153 | //attr >>= 1; // for framebuffer console |
147 | color[(attr >> 4) & 7], // bkgd color | 154 | ptr = G.attrbuf + sizeof("\033[")-1; |
148 | color[attr & 7] // text color | 155 | fg = (attr & 0x07); |
149 | ); | 156 | bold = (attr & 0x08); |
157 | bg = (attr & 0x70); | ||
158 | blink = (attr & 0x80); | ||
159 | if (G.last_bold > bold || G.last_blink > blink) { | ||
160 | G.last_bold = G.last_blink = 0; | ||
161 | G.last_bg = 0xff; | ||
162 | *ptr++ = '0'; | ||
163 | *ptr++ = ';'; | ||
164 | } | ||
165 | if (G.last_bold != bold) { | ||
166 | G.last_bold = bold; | ||
167 | *ptr++ = '1'; | ||
168 | *ptr++ = ';'; | ||
169 | } | ||
170 | if (G.last_blink != blink) { | ||
171 | G.last_blink = blink; | ||
172 | *ptr++ = '5'; | ||
173 | *ptr++ = ';'; | ||
174 | } | ||
175 | if (G.last_fg != fg) { | ||
176 | G.last_fg = fg; | ||
177 | *ptr++ = '3'; | ||
178 | *ptr++ = color[fg]; | ||
179 | *ptr++ = ';'; | ||
180 | } | ||
181 | if (G.last_bg != bg) { | ||
182 | G.last_bg = bg; | ||
183 | *ptr++ = '4'; | ||
184 | *ptr++ = color[bg >> 4]; | ||
185 | *ptr++ = ';'; | ||
186 | } | ||
187 | if (ptr != G.attrbuf + sizeof("\033[")-1) { | ||
188 | ptr[-1] = 'm'; | ||
189 | *ptr = '\0'; | ||
190 | fputs(G.attrbuf, stdout); | ||
191 | } | ||
150 | } | 192 | } |
151 | putchar(CHAR(data)); | 193 | putchar(CHAR(data)); |
194 | G.col++; | ||
152 | } | 195 | } |
153 | 196 | ||
154 | static void clrscr(void) | 197 | static void clrscr(void) |
155 | { | 198 | { |
156 | printf("\033[1;1H" "\033[0J"); | 199 | // Home, clear till end of src, cursor on |
200 | fputs("\033[1;1H" "\033[J" "\033[?25h", stdout); | ||
201 | G.curoff = G.col = G.line = 0; | ||
157 | } | 202 | } |
158 | 203 | ||
159 | static void curoff(void) | 204 | static void curoff(void) |
160 | { | 205 | { |
161 | printf("\033[?25l"); | 206 | if (!G.curoff) { |
207 | G.curoff = 1; | ||
208 | fputs("\033[?25l", stdout); | ||
209 | } | ||
162 | } | 210 | } |
163 | 211 | ||
164 | static void curon(void) | 212 | static void curon(void) |
165 | { | 213 | { |
166 | printf("\033[?25h"); | 214 | if (G.curoff) { |
215 | G.curoff = 0; | ||
216 | fputs("\033[?25h", stdout); | ||
217 | } | ||
167 | } | 218 | } |
168 | 219 | ||
169 | static void gotoxy(int row, int line) | 220 | static void gotoxy(int col, int line) |
170 | { | 221 | { |
171 | printf("\033[%u;%uH", line + 1, row + 1); | 222 | if (G.col != col || G.line != line) { |
223 | G.col = col; | ||
224 | G.line = line; | ||
225 | printf("\033[%u;%uH", line + 1, col + 1); | ||
226 | } | ||
172 | } | 227 | } |
173 | 228 | ||
174 | static void screen_dump(void) | 229 | static void screen_dump(void) |
175 | { | 230 | { |
176 | int linefeed_cnt; | 231 | int linefeed_cnt; |
177 | int line, row; | 232 | int line, col; |
178 | int linecnt = G.info.lines - G.y; | 233 | int linecnt = G.remote.lines - G.y; |
179 | char *data = G.data + G.current + (2 * G.y * G.info.rows); | 234 | char *data = G.data + G.current + (2 * G.y * G.remote.cols); |
180 | 235 | ||
181 | linefeed_cnt = 0; | 236 | linefeed_cnt = 0; |
182 | for (line = 0; line < linecnt && line < G.height; line++) { | 237 | for (line = 0; line < linecnt && line < G.height; line++) { |
183 | int space_cnt = 0; | 238 | int space_cnt = 0; |
184 | for (row = 0; row < G.info.rows; row++, NEXT(data)) { | 239 | for (col = 0; col < G.remote.cols; col++, NEXT(data)) { |
185 | unsigned tty_row = row - G.x; // if will catch row < G.x too | 240 | unsigned tty_col = col - G.x; // if will catch col < G.x too |
186 | 241 | ||
187 | if (tty_row >= G.width) | 242 | if (tty_col >= G.width) |
188 | continue; | 243 | continue; |
189 | space_cnt++; | 244 | space_cnt++; |
190 | if (BW && CHAR(data) == ' ') | 245 | if (BW && CHAR(data) == ' ') |
@@ -204,8 +259,8 @@ static void screen_dump(void) | |||
204 | 259 | ||
205 | static void curmove(void) | 260 | static void curmove(void) |
206 | { | 261 | { |
207 | unsigned cx = G.info.cursor_x - G.x; | 262 | unsigned cx = G.remote.cursor_x - G.x; |
208 | unsigned cy = G.info.cursor_y - G.y; | 263 | unsigned cy = G.remote.cursor_y - G.y; |
209 | 264 | ||
210 | if (cx >= G.width || cy >= G.height) { | 265 | if (cx >= G.width || cy >= G.height) { |
211 | curoff(); | 266 | curoff(); |
@@ -226,7 +281,7 @@ static void cleanup(int code) | |||
226 | } | 281 | } |
227 | // Reset attributes | 282 | // Reset attributes |
228 | if (!BW) | 283 | if (!BW) |
229 | printf("\033[0m"); | 284 | fputs("\033[0m", stdout); |
230 | bb_putchar('\n'); | 285 | bb_putchar('\n'); |
231 | if (code > 1) | 286 | if (code > 1) |
232 | kill_myself_with_sig(code); // does not return | 287 | kill_myself_with_sig(code); // does not return |
@@ -236,8 +291,8 @@ static void cleanup(int code) | |||
236 | static void get_initial_data(const char* vcsa_name) | 291 | static void get_initial_data(const char* vcsa_name) |
237 | { | 292 | { |
238 | G.vcsa_fd = xopen(vcsa_name, O_RDONLY); | 293 | G.vcsa_fd = xopen(vcsa_name, O_RDONLY); |
239 | xread(G.vcsa_fd, &G.info, 4); | 294 | xread(G.vcsa_fd, &G.remote, 4); |
240 | G.size = G.info.rows * G.info.lines * 2; | 295 | G.size = G.remote.cols * G.remote.lines * 2; |
241 | G.width = G.height = UINT_MAX; | 296 | G.width = G.height = UINT_MAX; |
242 | G.data = xzalloc(2 * G.size); | 297 | G.data = xzalloc(2 * G.size); |
243 | screen_read_close(); | 298 | screen_read_close(); |
@@ -354,34 +409,30 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) | |||
354 | int i, j; | 409 | int i, j; |
355 | char *data, *old; | 410 | char *data, *old; |
356 | 411 | ||
357 | old = G.data + G.current; | ||
358 | G.current = G.size - G.current; | ||
359 | data = G.data + G.current; | ||
360 | |||
361 | // Close & re-open vcsa in case they have | 412 | // Close & re-open vcsa in case they have |
362 | // swapped virtual consoles | 413 | // swapped virtual consoles |
363 | G.vcsa_fd = xopen(vcsa_name, O_RDONLY); | 414 | G.vcsa_fd = xopen(vcsa_name, O_RDONLY); |
364 | xread(G.vcsa_fd, &G.info, 4); | 415 | xread(G.vcsa_fd, &G.remote, 4); |
365 | if (G.size != (G.info.rows * G.info.lines * 2)) { | 416 | if (G.size != (G.remote.cols * G.remote.lines * 2)) { |
366 | cleanup(1); | 417 | cleanup(1); |
367 | } | 418 | } |
368 | i = G.width; | 419 | i = G.width; |
369 | j = G.height; | 420 | j = G.height; |
370 | get_terminal_width_height(G.kbd_fd, &G.width, &G.height); | 421 | get_terminal_width_height(G.kbd_fd, &G.width, &G.height); |
371 | if ((option_mask32 & FLAG(f))) { | 422 | if ((option_mask32 & FLAG(f))) { |
372 | int nx = G.info.cursor_x - G.width + 1; | 423 | int nx = G.remote.cursor_x - G.width + 1; |
373 | int ny = G.info.cursor_y - G.height + 1; | 424 | int ny = G.remote.cursor_y - G.height + 1; |
374 | 425 | ||
375 | if (G.info.cursor_x < G.x) { | 426 | if (G.remote.cursor_x < G.x) { |
376 | G.x = G.info.cursor_x; | 427 | G.x = G.remote.cursor_x; |
377 | i = 0; // force refresh | 428 | i = 0; // force refresh |
378 | } | 429 | } |
379 | if (nx > G.x) { | 430 | if (nx > G.x) { |
380 | G.x = nx; | 431 | G.x = nx; |
381 | i = 0; // force refresh | 432 | i = 0; // force refresh |
382 | } | 433 | } |
383 | if (G.info.cursor_y < G.y) { | 434 | if (G.remote.cursor_y < G.y) { |
384 | G.y = G.info.cursor_y; | 435 | G.y = G.remote.cursor_y; |
385 | i = 0; // force refresh | 436 | i = 0; // force refresh |
386 | } | 437 | } |
387 | if (ny > G.y) { | 438 | if (ny > G.y) { |
@@ -391,40 +442,43 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) | |||
391 | } | 442 | } |
392 | 443 | ||
393 | // Scan console data and redraw our tty where needed | 444 | // Scan console data and redraw our tty where needed |
445 | old = G.data + G.current; | ||
446 | G.current = G.size - G.current; | ||
447 | data = G.data + G.current; | ||
394 | screen_read_close(); | 448 | screen_read_close(); |
395 | if (i != G.width || j != G.height) { | 449 | if (i != G.width || j != G.height) { |
396 | clrscr(); | 450 | clrscr(); |
397 | screen_dump(); | 451 | screen_dump(); |
398 | } | 452 | } else { |
399 | else for (i = 0; i < G.info.lines; i++) { | 453 | // For each remote line |
400 | char *last = last; | 454 | old += G.y * G.remote.cols * 2; |
401 | char *first = NULL; | 455 | data += G.y * G.remote.cols * 2; |
402 | int iy = i - G.y; | 456 | for (i = G.y; i < G.remote.lines; i++) { |
403 | 457 | char *first = NULL; // first char which needs updating | |
404 | if (iy >= (int) G.height) | 458 | char *last = last; // last char which needs updating |
405 | break; | 459 | unsigned iy = i - G.y; |
406 | for (j = 0; j < G.info.rows; j++) { | 460 | |
407 | last = data; | 461 | if (iy >= G.height) |
408 | if (DATA(data) != DATA(old) && iy >= 0) { | 462 | break; |
463 | old += G.x * 2; | ||
464 | data += G.x * 2; | ||
465 | for (j = G.x; j < G.remote.cols; j++, NEXT(old), NEXT(data)) { | ||
409 | unsigned jx = j - G.x; | 466 | unsigned jx = j - G.x; |
410 | 467 | ||
411 | last = NULL; | 468 | if (jx < G.width && DATA(data) != DATA(old)) { |
412 | if (first == NULL && jx < G.width) { | 469 | last = data; |
413 | first = data; | 470 | if (!first) { |
414 | gotoxy(jx, iy); | 471 | first = data; |
472 | gotoxy(jx, iy); | ||
473 | } | ||
415 | } | 474 | } |
416 | } | 475 | } |
417 | NEXT(old); | 476 | if (first) { |
418 | NEXT(data); | 477 | // Rewrite updated data on the local screen |
478 | for (; first <= last; NEXT(first)) | ||
479 | screen_char(first); | ||
480 | } | ||
419 | } | 481 | } |
420 | if (first == NULL) | ||
421 | continue; | ||
422 | if (last == NULL) | ||
423 | last = data; | ||
424 | |||
425 | // Write the data to the screen | ||
426 | for (; first < last; NEXT(first)) | ||
427 | screen_char(first); | ||
428 | } | 482 | } |
429 | curmove(); | 483 | curmove(); |
430 | 484 | ||