ao_alsa: use "Master" mixer channel instead of "PCM" by default
[mplayer.git] / mp_msg.c
blob7b97d286e4679d0a4cdbabb14d5d32ab485807be
1 /*
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.
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stdarg.h>
22 #include <string.h>
24 #include "config.h"
25 #include "osdep/getch2.h"
26 #include "osdep/io.h"
28 #ifdef CONFIG_TRANSLATION
29 #include <locale.h>
30 #include <libintl.h>
31 #endif
33 #ifdef CONFIG_ICONV
34 #include <iconv.h>
35 #include <errno.h>
36 #endif
38 #include "mp_msg.h"
40 /* maximum message length of mp_msg */
41 #define MSGSIZE_MAX 3072
43 #ifdef _WIN32
44 #define WIN32_LEAN_AND_MEAN
45 #include <windows.h>
46 #include <io.h>
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] = {
52 FOREGROUND_RED,
53 FOREGROUND_GREEN,
54 FOREGROUND_GREEN | FOREGROUND_RED,
55 FOREGROUND_BLUE,
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
62 #endif
64 int mp_msg_levels[MSGT_MAX]; // verbose level of this module. initialized to -2
65 int mp_msg_level_all = MSGL_STATUS;
66 int verbose = 0;
67 int mp_msg_color = 0;
68 int mp_msg_module = 0;
69 #ifdef CONFIG_ICONV
70 char *mp_msg_charset = NULL;
71 static char *old_charset = NULL;
72 static iconv_t msgiconv;
73 #endif
75 const char* filename_recode(const char* filename)
77 #if !defined(CONFIG_ICONV) || !defined(MSG_CHARSET)
78 return filename;
79 #else
80 static iconv_t inv_msgiconv = (iconv_t)(-1);
81 static char recoded_filename[MSGSIZE_MAX];
82 size_t filename_len, max_path;
83 char* precoded;
84 if (!mp_msg_charset ||
85 !strcasecmp(mp_msg_charset, MSG_CHARSET) ||
86 !strcasecmp(mp_msg_charset, "noconv"))
87 return filename;
88 if (inv_msgiconv == (iconv_t)(-1)) {
89 inv_msgiconv = iconv_open(MSG_CHARSET, mp_msg_charset);
90 if (inv_msgiconv == (iconv_t)(-1))
91 return filename;
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] = '.';
99 precoded += 3;
101 *precoded = '\0';
102 return recoded_filename;
103 #endif
106 void mp_msg_init(void){
107 #ifdef _WIN32
108 CONSOLE_SCREEN_BUFFER_INFO cinfo;
109 long cmode = 0;
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;
116 #endif
117 int i;
118 char *env = getenv("MPLAYER_VERBOSE");
119 if (env)
120 verbose = atoi(env);
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
123 #ifdef CONFIG_ICONV
124 mp_msg_charset = getenv("MPLAYER_CHARSET");
125 if (!mp_msg_charset)
126 #ifdef _WIN32
127 mp_msg_charset = "UTF-8";
128 #else
129 mp_msg_charset = get_term_charset();
130 #endif
131 #endif
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");
139 #endif
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];
151 #ifdef MP_ANNOY_ME
152 /* that's only a silly color test */
154 int c;
155 static int flag = 1;
156 if (flag)
157 for(c = 0; c < 24; c++)
158 printf("\033[%d;3%dm*** COLOR TEST %d ***\n", c>7, c&7, c);
159 flag = 0;
161 #endif
162 if (mp_msg_color)
164 #ifdef _WIN32
165 HANDLE *wstream = stream == stderr ? hSTDERR : hSTDOUT;
166 SetConsoleTextAttribute(wstream, ansi2win32[c] | FOREGROUND_INTENSITY);
167 #else
168 fprintf(stream, "\033[%d;3%dm", c >> 3, c & 7);
169 #endif
173 static void print_msg_module(FILE* stream, int mod)
175 static const char *module_text[MSGT_MAX] = {
176 "GLOBAL",
177 "CPLAYER",
178 "GPLAYER",
179 "VIDEOOUT",
180 "AUDIOOUT",
181 "DEMUXER",
182 "DS",
183 "DEMUX",
184 "HEADER",
185 "AVSYNC",
186 "AUTOQ",
187 "CFGPARSER",
188 "DECAUDIO",
189 "DECVIDEO",
190 "SEEK",
191 "WIN32",
192 "OPEN",
193 "DVD",
194 "PARSEES",
195 "LIRC",
196 "STREAM",
197 "CACHE",
198 "MENCODER",
199 "XACODEC",
200 "TV",
201 "OSDEP",
202 "SPUDEC",
203 "PLAYTREE",
204 "INPUT",
205 "VFILTER",
206 "OSD",
207 "NETWORK",
208 "CPUDETECT",
209 "CODECCFG",
210 "SWS",
211 "VOBSUB",
212 "SUBREADER",
213 "AFILTER",
214 "NETST",
215 "MUXER",
216 "OSDMENU",
217 "IDENTIFY",
218 "RADIO",
219 "ASS",
220 "LOADER",
221 "STATUSLINE",
223 int c2 = (mod + 1) % 15 + 1;
225 if (!mp_msg_module)
226 return;
227 #ifdef _WIN32
228 HANDLE *wstream = stream == stderr ? hSTDERR : hSTDOUT;
229 if (mp_msg_color)
230 SetConsoleTextAttribute(wstream, ansi2win32[c2&7] | FOREGROUND_INTENSITY);
231 fprintf(stream, "%9s", module_text[mod]);
232 if (mp_msg_color)
233 SetConsoleTextAttribute(wstream, stdoutAttrs);
234 #else
235 if (mp_msg_color)
236 fprintf(stream, "\033[%d;3%dm", c2 >> 3, c2 & 7);
237 fprintf(stream, "%9s", module_text[mod]);
238 if (mp_msg_color)
239 fprintf(stream, "\033[0;37m");
240 #endif
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))
265 if (old_charset)
267 free(old_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);
279 else
281 memset(tmp2, 0, MSGSIZE_MAX);
283 while (iconv(msgiconv, &in, &inlen, &out, &outlen) == -1)
285 if (!inlen || !outlen)
286 break;
287 *out++ = *in++;
288 outlen--; inlen--;
291 strncpy(tmp, tmp2, MSGSIZE_MAX);
292 tmp[MSGSIZE_MAX-1] = 0;
293 tmp[MSGSIZE_MAX-2] = '\n';
296 #endif
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;
305 if (header)
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);
314 if (mp_msg_color)
316 #ifdef _WIN32
317 HANDLE *wstream = lev <= MSGL_WARN ? hSTDERR : hSTDOUT;
318 SetConsoleTextAttribute(wstream, stdoutAttrs);
319 #else
320 fprintf(stream, "\033[0m");
321 #endif
323 fflush(stream);
326 void mp_msg(int mod, int lev, const char *format, ...)
328 va_list va;
329 va_start(va, format);
330 mp_msg_va(mod, lev, format, va);
331 va_end(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
340 * general).
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
345 * locale.
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");
383 #endif
384 return (char *)string;
387 void mp_tmsg(int mod, int lev, const char *format, ...)
389 va_list va;
390 va_start(va, format);
391 mp_msg_va(mod, lev, mp_gtext(format), va);
392 va_end(va);