summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-08-21 22:11:38 +0200
committerwm4 <wm4@nowhere>2014-08-21 22:45:58 +0200
commit47b29094c34bdf0aab9f213c8eb2347993e4d505 (patch)
tree3c68821d10cd713c6d515705b79d1513160bd494
parent218ace2b02e2f2a867c4b792d4a1ec03015d7294 (diff)
downloadmpv-47b29094c34bdf0aab9f213c8eb2347993e4d505.tar.bz2
mpv-47b29094c34bdf0aab9f213c8eb2347993e4d505.tar.xz
win32: emulate some ANSI terminal escape codes
We already redirect all terminal output through our own wrappers (for the sake of UTF-8), so we might as well use it to handle ANSI escape codes. This also changes behavior on UNIX: we don't retrieve some escape codes per terminfo anymore, and just hardcode them. Every terminal should understand them. The advantage is that we can pretend to have a real terminal in the normal player code, and Windows atrocities are locked away in glue code.
-rw-r--r--common/msg.c28
-rw-r--r--osdep/io.c10
-rw-r--r--osdep/terminal-unix.c19
-rw-r--r--osdep/terminal-win.c84
-rw-r--r--osdep/terminal.h10
5 files changed, 98 insertions, 53 deletions
diff --git a/common/msg.c b/common/msg.c
index d1c2530c2c..7f278b1840 100644
--- a/common/msg.c
+++ b/common/msg.c
@@ -158,16 +158,10 @@ static void prepare_status_line(struct mp_log_root *root, char *new_status)
size_t clear_lines = MPMIN(MPMAX(new_lines, old_lines), root->blank_lines);
// clear the status line itself
- if (terminal_erase_to_end_of_line[0]) {
- fprintf(f, "\r%s", terminal_erase_to_end_of_line);
- } else {
- // This code is for MS windows (no ANSI control sequences)
- get_screen_size();
- fprintf(f, "\r%*s\r", screen_width - 1, "");
- }
+ fprintf(f, "\r\033[K");
// and clear all previous old lines
for (size_t n = 1; n < clear_lines; n++)
- fprintf(f, "%s\r%s", terminal_cursor_up, terminal_erase_to_end_of_line);
+ fprintf(f, "\033[A\r\033[K");
// skip "unused" blank lines, so that status is aligned to term bottom
for (size_t n = new_lines; n < clear_lines; n++)
fprintf(f, "\n");
@@ -200,10 +194,20 @@ bool mp_msg_has_status_line(struct mpv_global *global)
return r;
}
+static void set_term_color(FILE *stream, int c)
+{
+ if (c == -1) {
+ fprintf(stream, "\033[0m");
+ } else {
+ fprintf(stream, "\033[%d;3%dm", c >> 3, c & 7);
+ }
+}
+
+
static void set_msg_color(FILE* stream, int lev)
{
static const int v_colors[] = {9, 1, 3, -1, -1, 2, 8, 8, 8, -1};
- terminal_set_foreground_color(stream, v_colors[lev]);
+ set_term_color(stream, v_colors[lev]);
}
static void pretty_print_module(FILE* stream, const char *prefix, bool use_color, int lev)
@@ -214,12 +218,12 @@ static void pretty_print_module(FILE* stream, const char *prefix, bool use_color
unsigned int mod = 0;
for (int i = 0; i < prefix_len; ++i)
mod = mod * 33 + prefix[i];
- terminal_set_foreground_color(stream, (mod + 1) % 15 + 1);
+ set_term_color(stream, (mod + 1) % 15 + 1);
}
fprintf(stream, "%10s", prefix);
if (use_color)
- terminal_set_foreground_color(stream, -1);
+ set_term_color(stream, -1);
fprintf(stream, ": ");
if (use_color)
set_msg_color(stream, lev);
@@ -291,7 +295,7 @@ static void print_msg_on_terminal(struct mp_log *log, int lev, char *text)
fprintf(stream, "%s", terminate);
if (root->color)
- terminal_set_foreground_color(stream, -1);
+ set_term_color(stream, -1);
fflush(stream);
}
diff --git a/osdep/io.c b/osdep/io.c
index 8423a6beff..cc90f145d9 100644
--- a/osdep/io.c
+++ b/osdep/io.c
@@ -25,6 +25,7 @@
#include "config.h"
#include "osdep/io.h"
+#include "osdep/terminal.h"
// Set the CLOEXEC flag on the given fd.
// On error, false is returned (and errno set).
@@ -179,13 +180,10 @@ static int mp_vfprintf(FILE *stream, const char *format, va_list args)
char *buf = talloc_array(NULL, char, len);
if (buf) {
- vsnprintf(buf, len, format, args);
- wchar_t *out = mp_from_utf8(NULL, buf);
- size_t out_len = wcslen(out);
- talloc_free(buf);
- done = WriteConsoleW(wstream, out, out_len, NULL, NULL);
- talloc_free(out);
+ done = vsnprintf(buf, len, format, args);
+ mp_write_console_ansi(wstream, buf);
}
+ talloc_free(buf);
} else {
done = vfprintf(stream, format, args);
}
diff --git a/osdep/terminal-unix.c b/osdep/terminal-unix.c
index 499ad73394..b17ede6670 100644
--- a/osdep/terminal-unix.c
+++ b/osdep/terminal-unix.c
@@ -54,8 +54,6 @@ static volatile int tio_orig_set;
int screen_width = 80;
int screen_height = 24;
-char *terminal_erase_to_end_of_line = "\033[K";
-char *terminal_cursor_up = "\033[A";
typedef struct {
char *cap;
@@ -271,19 +269,11 @@ static int load_termcap(char *termtype){
static char term_buf[128];
char *buf_ptr = &term_buf[0];
- char *tmp;
// References for terminfo/termcap codes:
// http://linux.die.net/man/5/termcap
// http://unixhelp.ed.ac.uk/CGI/man-cgi?terminfo+5
- tmp = tgetstr("ce", &buf_ptr);
- if (tmp)
- terminal_erase_to_end_of_line = tmp;
- tmp = tgetstr("up", &buf_ptr);
- if (tmp)
- terminal_cursor_up = tmp;
-
screen_width = tgetnum("co");
screen_height = tgetnum("li");
if (screen_width < 1 || screen_width > 255)
@@ -614,15 +604,6 @@ bool terminal_in_background(void)
return isatty(2) && tcgetpgrp(2) != getpgrp();
}
-void terminal_set_foreground_color(FILE *stream, int c)
-{
- if (c == -1) {
- fprintf(stream, "\033[0m");
- } else {
- fprintf(stream, "\033[%d;3%dm", c >> 3, c & 7);
- }
-}
-
int terminal_init(void)
{
if (isatty(1))
diff --git a/osdep/terminal-win.c b/osdep/terminal-win.c
index 19603d87d1..9b985d7378 100644
--- a/osdep/terminal-win.c
+++ b/osdep/terminal-win.c
@@ -33,12 +33,11 @@
#include "input/keycodes.h"
#include "input/input.h"
#include "terminal.h"
+#include "osdep/io.h"
#include "osdep/w32_keyboard.h"
int screen_width = 79;
int screen_height = 24;
-char *terminal_erase_to_end_of_line = "";
-char *terminal_cursor_up = "";
#define hSTDOUT GetStdHandle(STD_OUTPUT_HANDLE)
#define hSTDERR GetStdHandle(STD_ERROR_HANDLE)
@@ -58,7 +57,7 @@ void get_screen_size(void)
{
CONSOLE_SCREEN_BUFFER_INFO cinfo;
if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cinfo)) {
- screen_width = cinfo.dwMaximumWindowSize.X;
+ screen_width = cinfo.dwMaximumWindowSize.X - 1;
screen_height = cinfo.dwMaximumWindowSize.Y;
}
}
@@ -177,13 +176,80 @@ bool terminal_in_background(void)
return false;
}
-void terminal_set_foreground_color(FILE *stream, int c)
+static void write_console_text(HANDLE *wstream, char *buf)
{
- HANDLE *wstream = stream == stderr ? hSTDERR : hSTDOUT;
- if (c < 0 || c >= 8) { // reset or invalid
- SetConsoleTextAttribute(wstream, stdoutAttrs);
- } else {
- SetConsoleTextAttribute(wstream, ansi2win32[c] | FOREGROUND_INTENSITY);
+ wchar_t *out = mp_from_utf8(NULL, buf);
+ size_t out_len = wcslen(out);
+ WriteConsoleW(wstream, out, out_len, NULL, NULL);
+ talloc_free(out);
+}
+
+// Mutates the input argument (buf), because we're evil.
+void mp_write_console_ansi(HANDLE *wstream, char *buf)
+{
+ while (*buf) {
+ char *next = strchr(buf, '\033');
+ if (!next) {
+ write_console_text(wstream, buf);
+ break;
+ }
+ next[0] = '\0'; // mutate input for fun and profit
+ write_console_text(wstream, buf);
+ if (next[1] != '[') {
+ write_console_text(wstream, "\033");
+ buf = next;
+ continue;
+ }
+ next += 2;
+ // ANSI codes generally follow this syntax:
+ // "\033[" [ <i> (';' <i> )* ] <c>
+ // where <i> are integers, and <c> a single char command code.
+ // Also see: http://en.wikipedia.org/wiki/ANSI_escape_code#CSI_codes
+ int params[2] = {-1, -1}; // 'm' might be unlimited; ignore that
+ int num_params = 0;
+ while (num_params < 2) {
+ char *end = next;
+ long p = strtol(next, &end, 10);
+ if (end == next)
+ break;
+ next = end;
+ params[num_params++] = p;
+ if (next[0] != ';' || !next[0])
+ break;
+ next += 1;
+ }
+ char code = next[0];
+ if (code)
+ next += 1;
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ GetConsoleScreenBufferInfo(wstream, &info);
+ switch (code) {
+ case 'K': { // erase to end of line
+ COORD at = info.dwCursorPosition;
+ int len = info.dwSize.X - at.X;
+ FillConsoleOutputCharacterW(wstream, ' ', len, at, &(DWORD){0});
+ SetConsoleCursorPosition(wstream, at);
+ break;
+ }
+ case 'A': { // cursor up
+ info.dwCursorPosition.Y -= 1;
+ SetConsoleCursorPosition(wstream, info.dwCursorPosition);
+ break;
+ }
+ case 'm': { // "SGR"
+ for (int n = 0; n < num_params; n++) {
+ int p = params[n];
+ if (p <= 0) {
+ SetConsoleTextAttribute(wstream, stdoutAttrs);
+ } else if (p >= 0 && p < 8) {
+ SetConsoleTextAttribute(wstream,
+ ansi2win32[p] | FOREGROUND_INTENSITY);
+ }
+ }
+ break;
+ }
+ }
+ buf = next;
}
}
diff --git a/osdep/terminal.h b/osdep/terminal.h
index 4495bfb471..491d76975b 100644
--- a/osdep/terminal.h
+++ b/osdep/terminal.h
@@ -33,9 +33,6 @@ struct input_ctx;
extern int screen_width;
extern int screen_height;
-extern char *terminal_erase_to_end_of_line;
-extern char *terminal_cursor_up;
-
/* Global initialization for terminal output. */
int terminal_init(void);
@@ -45,10 +42,6 @@ void terminal_setup_getch(struct input_ctx *ictx);
/* Return whether the process has been backgrounded. */
bool terminal_in_background(void);
-/* Set ANSI text foreground color. c is [-1, 7], where 0-7 are colors, and
- * -1 means reset to default. stream is either stdout or stderr. */
-void terminal_set_foreground_color(FILE *stream, int c);
-
/* Get screen-size using IOCTL call. */
void get_screen_size(void);
@@ -59,4 +52,7 @@ void getch2_disable(void);
/* Enable and disable STDIN line-buffering */
void getch2_poll(void);
+// Windows only.
+void mp_write_console_ansi(void **wstream, char *buf);
+
#endif /* MPLAYER_GETCH2_H */