2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "osdep/getch2.h"
28 #ifdef CONFIG_TRANSLATION
40 /* maximum message length of mp_msg */
41 #define MSGSIZE_MAX 3072
44 #define WIN32_LEAN_AND_MEAN
47 #define hSTDOUT GetStdHandle(STD_OUTPUT_HANDLE)
48 #define hSTDERR GetStdHandle(STD_ERROR_HANDLE)
49 static short stdoutAttrs
= 0;
50 static const unsigned char ansi2win32
[10] = {
54 FOREGROUND_GREEN
| FOREGROUND_RED
,
56 FOREGROUND_BLUE
| FOREGROUND_RED
,
57 FOREGROUND_BLUE
| FOREGROUND_GREEN
,
58 FOREGROUND_BLUE
| FOREGROUND_GREEN
| FOREGROUND_RED
,
59 FOREGROUND_BLUE
| FOREGROUND_GREEN
| FOREGROUND_RED
,
60 FOREGROUND_BLUE
| FOREGROUND_GREEN
| FOREGROUND_RED
64 int mp_msg_levels
[MSGT_MAX
]; // verbose level of this module. initialized to -2
65 int mp_msg_level_all
= MSGL_STATUS
;
68 int mp_msg_module
= 0;
70 char *mp_msg_charset
= NULL
;
71 static char *old_charset
= NULL
;
72 static iconv_t msgiconv
;
75 const char* filename_recode(const char* filename
)
77 #if !defined(CONFIG_ICONV) || !defined(MSG_CHARSET)
80 static iconv_t inv_msgiconv
= (iconv_t
)(-1);
81 static char recoded_filename
[MSGSIZE_MAX
];
82 size_t filename_len
, max_path
;
84 if (!mp_msg_charset
||
85 !strcasecmp(mp_msg_charset
, MSG_CHARSET
) ||
86 !strcasecmp(mp_msg_charset
, "noconv"))
88 if (inv_msgiconv
== (iconv_t
)(-1)) {
89 inv_msgiconv
= iconv_open(MSG_CHARSET
, mp_msg_charset
);
90 if (inv_msgiconv
== (iconv_t
)(-1))
93 filename_len
= strlen(filename
);
94 max_path
= MSGSIZE_MAX
- 4;
95 precoded
= recoded_filename
;
96 if (iconv(inv_msgiconv
, (char **)&filename
, &filename_len
,
97 &precoded
, &max_path
) == (size_t)(-1) && errno
== E2BIG
) {
98 precoded
[0] = precoded
[1] = precoded
[2] = '.';
102 return recoded_filename
;
106 void mp_msg_init(void){
108 CONSOLE_SCREEN_BUFFER_INFO cinfo
;
110 GetConsoleMode(hSTDOUT
, &cmode
);
111 cmode
|= (ENABLE_PROCESSED_OUTPUT
| ENABLE_WRAP_AT_EOL_OUTPUT
);
112 SetConsoleMode(hSTDOUT
, cmode
);
113 SetConsoleMode(hSTDERR
, cmode
);
114 GetConsoleScreenBufferInfo(hSTDOUT
, &cinfo
);
115 stdoutAttrs
= cinfo
.wAttributes
;
118 char *env
= getenv("MPLAYER_VERBOSE");
121 for(i
=0;i
<MSGT_MAX
;i
++) mp_msg_levels
[i
] = -2;
122 mp_msg_levels
[MSGT_IDENTIFY
] = -1; // no -identify output by default
124 mp_msg_charset
= getenv("MPLAYER_CHARSET");
127 mp_msg_charset
= "UTF-8";
129 mp_msg_charset
= get_term_charset();
132 #ifdef CONFIG_TRANSLATION
133 textdomain("mplayer");
134 char *localedir
= getenv("MPLAYER_LOCALEDIR");
135 if (localedir
== NULL
&& strlen(MPLAYER_LOCALEDIR
))
136 localedir
= MPLAYER_LOCALEDIR
;
137 bindtextdomain("mplayer", localedir
);
138 bind_textdomain_codeset("mplayer", "UTF-8");
142 int mp_msg_test(int mod
, int lev
)
144 return lev
<= (mp_msg_levels
[mod
] == -2 ? mp_msg_level_all
+ verbose
: mp_msg_levels
[mod
]);
147 static void set_msg_color(FILE* stream
, int lev
)
149 static const unsigned char v_colors
[10] = {9, 1, 3, 15, 7, 2, 2, 8, 8, 8};
150 int c
= v_colors
[lev
];
152 /* that's only a silly color test */
157 for(c
= 0; c
< 24; c
++)
158 printf("\033[%d;3%dm*** COLOR TEST %d ***\n", c
>7, c
&7, c
);
165 HANDLE
*wstream
= stream
== stderr
? hSTDERR
: hSTDOUT
;
166 SetConsoleTextAttribute(wstream
, ansi2win32
[c
] | FOREGROUND_INTENSITY
);
168 fprintf(stream
, "\033[%d;3%dm", c
>> 3, c
& 7);
173 static void print_msg_module(FILE* stream
, int mod
)
175 static const char *module_text
[MSGT_MAX
] = {
223 int c2
= (mod
+ 1) % 15 + 1;
228 HANDLE
*wstream
= stream
== stderr
? hSTDERR
: hSTDOUT
;
230 SetConsoleTextAttribute(wstream
, ansi2win32
[c2
&7] | FOREGROUND_INTENSITY
);
231 fprintf(stream
, "%9s", module_text
[mod
]);
233 SetConsoleTextAttribute(wstream
, stdoutAttrs
);
236 fprintf(stream
, "\033[%d;3%dm", c2
>> 3, c2
& 7);
237 fprintf(stream
, "%9s", module_text
[mod
]);
239 fprintf(stream
, "\033[0;37m");
241 fprintf(stream
, ": ");
244 void mp_msg_va(int mod
, int lev
, const char *format
, va_list va
)
246 char tmp
[MSGSIZE_MAX
];
247 FILE *stream
= lev
<= MSGL_WARN
? stderr
: stdout
;
248 static int header
= 1;
249 // indicates if last line printed was a status line
250 static int statusline
;
252 if (!mp_msg_test(mod
, lev
)) return; // do not display
253 vsnprintf(tmp
, MSGSIZE_MAX
, format
, va
);
254 tmp
[MSGSIZE_MAX
-2] = '\n';
255 tmp
[MSGSIZE_MAX
-1] = 0;
257 #if defined(CONFIG_ICONV) && defined(MSG_CHARSET)
258 if (mp_msg_charset
&& strcasecmp(mp_msg_charset
, "noconv"))
260 char tmp2
[MSGSIZE_MAX
];
261 size_t inlen
= strlen(tmp
), outlen
= MSGSIZE_MAX
;
262 char *in
= tmp
, *out
= tmp2
;
263 if (!old_charset
|| strcmp(old_charset
, mp_msg_charset
))
268 iconv_close(msgiconv
);
270 msgiconv
= iconv_open(mp_msg_charset
, MSG_CHARSET
);
271 old_charset
= strdup(mp_msg_charset
);
274 if (msgiconv
== (iconv_t
)(-1))
276 fprintf(stderr
,"iconv: conversion from %s to %s unsupported\n"
277 ,MSG_CHARSET
,mp_msg_charset
);
281 memset(tmp2
, 0, MSGSIZE_MAX
);
283 while (iconv(msgiconv
, &in
, &inlen
, &out
, &outlen
) == -1)
285 if (!inlen
|| !outlen
)
291 strncpy(tmp
, tmp2
, MSGSIZE_MAX
);
292 tmp
[MSGSIZE_MAX
-1] = 0;
293 tmp
[MSGSIZE_MAX
-2] = '\n';
298 /* A status line is normally intended to be overwritten by the next
299 * status line, and does not end with a '\n'. If we're printing a normal
300 * line instead after the status one print '\n' to change line. */
301 if (statusline
&& lev
!= MSGL_STATUS
)
302 fprintf(stream
, "\n");
303 statusline
= lev
== MSGL_STATUS
;
306 print_msg_module(stream
, mod
);
307 set_msg_color(stream
, lev
);
309 size_t len
= strlen(tmp
);
310 header
= len
&& (tmp
[len
-1] == '\n' || tmp
[len
-1] == '\r');
312 fprintf(stream
, "%s", tmp
);
317 HANDLE
*wstream
= lev
<= MSGL_WARN
? hSTDERR
: hSTDOUT
;
318 SetConsoleTextAttribute(wstream
, stdoutAttrs
);
320 fprintf(stream
, "\033[0m");
326 void mp_msg(int mod
, int lev
, const char *format
, ...)
329 va_start(va
, format
);
330 mp_msg_va(mod
, lev
, format
, va
);
334 char *mp_gtext(const char *string
)
336 #ifdef CONFIG_TRANSLATION
337 /* gettext expects the global locale to be set with
338 * setlocale(LC_ALL, ""). However doing that would suck for a
339 * couple of reasons (locale stuff is badly designed and sucks in
342 * First, setting the locale, especially LC_CTYPE, changes the
343 * behavior of various C functions and we don't want that - we
344 * want isalpha() for example to always behave like in the C
347 * Second, there is no way to enforce a sane character set. All
348 * strings inside MPlayer must always be in utf-8, not in the
349 * character set specified by the system locale which could be
350 * something different and completely insane. The locale system
351 * lacks any way to say "set LC_CTYPE to utf-8, ignoring the
352 * default system locale if it specifies something different". We
353 * could try to work around that flaw by leaving LC_CTYPE to the C
354 * locale and only setting LC_MESSAGES (which is the variable that
355 * must be set to tell gettext which language to translate
356 * to). However if we leave LC_MESSAGES set then things like
357 * strerror() may produce completely garbled output when they try
358 * to translate their results but then try to convert some
359 * translated non-ASCII text to the character set specified by
360 * LC_CTYPE which would still be in the C locale (this doesn't
361 * affect gettext itself because it supports specifying the
362 * character set directly with bind_textdomain_codeset()).
364 * So the only solution (at least short of trying to work around
365 * things possibly producing non-utf-8 output) is to leave all the
366 * locale variables unset. Note that this means it's not possible
367 * to get translated output from any libraries we call if they
368 * only rely on the broken locale system to specify the language
369 * to use; this is the case with libc for example.
371 * The locale changing below is rather ugly, but hard to avoid.
372 * gettext doesn't support specifying the translation target
373 * directly, only through locale.
374 * The main actual problem this could cause is interference with
375 * other threads; that could be avoided with thread-specific
376 * locale changes, but such functionality is less standard and I
377 * think it's not worth adding pre-emptively unless someone sees
378 * an actual problem case.
380 setlocale(LC_MESSAGES
, "");
381 string
= gettext(string
);
382 setlocale(LC_MESSAGES
, "C");
384 return (char *)string
;
387 void mp_tmsg(int mod
, int lev
, const char *format
, ...)
390 va_start(va
, format
);
391 mp_msg_va(mod
, lev
, mp_gtext(format
), va
);