Merge svn changes up to r30463
[mplayer/kovensky.git] / mp_msg.c
blob9da2c3095b01232be3bdfbbf413eb93e016f9425
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdarg.h>
4 #include <string.h>
6 #include "config.h"
8 #ifdef CONFIG_TRANSLATION
9 #include <locale.h>
10 #include <libintl.h>
11 #endif
13 #ifdef CONFIG_ICONV
14 #include <iconv.h>
15 #include <errno.h>
16 /**
17 * \brief gets the name of the system's terminal character set
18 * \return a malloced string indicating the system charset
20 * Be warned that this function on many systems is in no way thread-safe
21 * since it modifies global data
23 char* get_term_charset(void);
24 #endif
26 #include "mp_msg.h"
28 /* maximum message length of mp_msg */
29 #define MSGSIZE_MAX 3072
31 int mp_msg_levels[MSGT_MAX]; // verbose level of this module. initialized to -2
32 int mp_msg_level_all = MSGL_STATUS;
33 int verbose = 0;
34 int mp_msg_color = 0;
35 int mp_msg_module = 0;
36 #ifdef CONFIG_ICONV
37 char *mp_msg_charset = NULL;
38 static char *old_charset = NULL;
39 static iconv_t msgiconv;
40 #endif
42 const char* filename_recode(const char* filename)
44 #if !defined(CONFIG_ICONV) || !defined(MSG_CHARSET)
45 return filename;
46 #else
47 static iconv_t inv_msgiconv = (iconv_t)(-1);
48 static char recoded_filename[MSGSIZE_MAX];
49 size_t filename_len, max_path;
50 char* precoded;
51 if (!mp_msg_charset ||
52 !strcasecmp(mp_msg_charset, MSG_CHARSET) ||
53 !strcasecmp(mp_msg_charset, "noconv"))
54 return filename;
55 if (inv_msgiconv == (iconv_t)(-1)) {
56 inv_msgiconv = iconv_open(MSG_CHARSET, mp_msg_charset);
57 if (inv_msgiconv == (iconv_t)(-1))
58 return filename;
60 filename_len = strlen(filename);
61 max_path = MSGSIZE_MAX - 4;
62 precoded = recoded_filename;
63 if (iconv(inv_msgiconv, &filename, &filename_len,
64 &precoded, &max_path) == (size_t)(-1) && errno == E2BIG) {
65 precoded[0] = precoded[1] = precoded[2] = '.';
66 precoded += 3;
68 *precoded = '\0';
69 return recoded_filename;
70 #endif
73 void mp_msg_init(void){
74 int i;
75 char *env = getenv("MPLAYER_VERBOSE");
76 if (env)
77 verbose = atoi(env);
78 for(i=0;i<MSGT_MAX;i++) mp_msg_levels[i] = -2;
79 mp_msg_levels[MSGT_IDENTIFY] = -1; // no -identify output by default
80 #ifdef CONFIG_ICONV
81 mp_msg_charset = getenv("MPLAYER_CHARSET");
82 if (!mp_msg_charset)
83 mp_msg_charset = get_term_charset();
84 #endif
85 #ifdef CONFIG_TRANSLATION
86 textdomain("mplayer");
87 char *localedir = getenv("MPLAYER_LOCALEDIR");
88 if (localedir == NULL && strlen(MPLAYER_LOCALEDIR))
89 localedir = MPLAYER_LOCALEDIR;
90 bindtextdomain("mplayer", localedir);
91 bind_textdomain_codeset("mplayer", "UTF-8");
92 #endif
95 int mp_msg_test(int mod, int lev)
97 return lev <= (mp_msg_levels[mod] == -2 ? mp_msg_level_all + verbose : mp_msg_levels[mod]);
100 static void set_msg_color(FILE* stream, int lev)
102 static const unsigned char v_colors[10] = {9, 1, 3, 15, 7, 2, 2, 8, 8, 8};
103 int c = v_colors[lev];
104 #ifdef MP_ANNOY_ME
105 /* that's only a silly color test */
107 int c;
108 static int flag = 1;
109 if (flag)
110 for(c = 0; c < 24; c++)
111 printf("\033[%d;3%dm*** COLOR TEST %d ***\n", c>7, c&7, c);
112 flag = 0;
114 #endif
115 if (mp_msg_color)
116 fprintf(stream, "\033[%d;3%dm", c >> 3, c & 7);
119 static void print_msg_module(FILE* stream, int mod)
121 static const char *module_text[MSGT_MAX] = {
122 "GLOBAL",
123 "CPLAYER",
124 "GPLAYER",
125 "VIDEOOUT",
126 "AUDIOOUT",
127 "DEMUXER",
128 "DS",
129 "DEMUX",
130 "HEADER",
131 "AVSYNC",
132 "AUTOQ",
133 "CFGPARSER",
134 "DECAUDIO",
135 "DECVIDEO",
136 "SEEK",
137 "WIN32",
138 "OPEN",
139 "DVD",
140 "PARSEES",
141 "LIRC",
142 "STREAM",
143 "CACHE",
144 "MENCODER",
145 "XACODEC",
146 "TV",
147 "OSDEP",
148 "SPUDEC",
149 "PLAYTREE",
150 "INPUT",
151 "VFILTER",
152 "OSD",
153 "NETWORK",
154 "CPUDETECT",
155 "CODECCFG",
156 "SWS",
157 "VOBSUB",
158 "SUBREADER",
159 "AFILTER",
160 "NETST",
161 "MUXER",
162 "OSDMENU",
163 "IDENTIFY",
164 "RADIO",
165 "ASS",
166 "LOADER",
167 "STATUSLINE",
169 int c2 = (mod + 1) % 15 + 1;
171 if (!mp_msg_module)
172 return;
173 if (mp_msg_color)
174 fprintf(stream, "\033[%d;3%dm", c2 >> 3, c2 & 7);
175 fprintf(stream, "%9s", module_text[mod]);
176 if (mp_msg_color)
177 fprintf(stream, "\033[0;37m");
178 fprintf(stream, ": ");
181 void mp_msg_va(int mod, int lev, const char *format, va_list va)
183 char tmp[MSGSIZE_MAX];
184 FILE *stream = lev <= MSGL_WARN ? stderr : stdout;
185 static int header = 1;
187 if (!mp_msg_test(mod, lev)) return; // do not display
188 vsnprintf(tmp, MSGSIZE_MAX, format, va);
189 tmp[MSGSIZE_MAX-2] = '\n';
190 tmp[MSGSIZE_MAX-1] = 0;
192 #if defined(CONFIG_ICONV) && defined(MSG_CHARSET)
193 if (mp_msg_charset && strcasecmp(mp_msg_charset, "noconv")) {
194 char tmp2[MSGSIZE_MAX];
195 size_t inlen = strlen(tmp), outlen = MSGSIZE_MAX;
196 char *in = tmp, *out = tmp2;
197 if (!old_charset || strcmp(old_charset, mp_msg_charset)) {
198 if (old_charset) {
199 free(old_charset);
200 iconv_close(msgiconv);
202 msgiconv = iconv_open(mp_msg_charset, MSG_CHARSET);
203 old_charset = strdup(mp_msg_charset);
205 if (msgiconv == (iconv_t)(-1)) {
206 fprintf(stderr,"iconv: conversion from %s to %s unsupported\n"
207 ,MSG_CHARSET,mp_msg_charset);
208 }else{
209 memset(tmp2, 0, MSGSIZE_MAX);
210 while (iconv(msgiconv, &in, &inlen, &out, &outlen) == -1) {
211 if (!inlen || !outlen)
212 break;
213 *out++ = *in++;
214 outlen--; inlen--;
216 strncpy(tmp, tmp2, MSGSIZE_MAX);
217 tmp[MSGSIZE_MAX-1] = 0;
218 tmp[MSGSIZE_MAX-2] = '\n';
221 #endif
223 if (header)
224 print_msg_module(stream, mod);
225 set_msg_color(stream, lev);
226 header = tmp[strlen(tmp)-1] == '\n' || tmp[strlen(tmp)-1] == '\r';
228 fprintf(stream, "%s", tmp);
229 fflush(stream);
232 void mp_msg(int mod, int lev, const char *format, ...)
234 va_list va;
235 va_start(va, format);
236 mp_msg_va(mod, lev, format, va);
237 va_end(va);
240 char *mp_gtext(const char *string)
242 #ifdef CONFIG_TRANSLATION
243 /* gettext expects the global locale to be set with
244 * setlocale(LC_ALL, ""). However doing that would suck for a
245 * couple of reasons (locale stuff is badly designed and sucks in
246 * general).
248 * First setting the locale, especially LC_CTYPE, changes the
249 * behavior of various C functions and we don't want that - we
250 * want isalpha() for example to always behave like in the C
251 * locale.
253 * Second, there is no way to enforce a sane character set. All
254 * strings inside MPlayer must always be in utf-8, not in the
255 * character set specified by the system locale which could be
256 * something different and completely insane. The locale system
257 * lacks any way to say "set LC_CTYPE to utf-8, ignoring the
258 * default system locale if it specifies something different". We
259 * could try to work around that flaw by leaving LC_CTYPE to the C
260 * locale and only setting LC_MESSAGES (which is the variable that
261 * must be set to tell gettext which language to translate
262 * to). However if we leave LC_MESSAGES set then things like
263 * strerror() may produce completely garbled output when they try
264 * to translate their results but then try to convert some
265 * translated non-ASCII text to the character set specified by
266 * LC_CTYPE which would still be in the C locale (this doesn't
267 * affect gettext itself because it supports specifying the
268 * character set directly with bind_textdomain_codeset()).
270 * So the only solution (at leat short of trying to work around
271 * things possibly producing non-utf-8 output) is to leave all the
272 * locale variables unset. Note that this means it's not possible
273 * to get translated output from any libraries we call if they
274 * only rely on the broken locale system to specify the language
275 * to use; this is the case with libc for example.
277 * The locale changing below is rather ugly, but hard to avoid.
278 * gettext doesn't support specifying the translation target
279 * directly, only through locale.
280 * The main actual problem this could cause is interference with
281 * other threads; that could be avoided with thread-specific
282 * locale changes, but such functionality is less standard and I
283 * think it's not worth adding pre-emptively unless someone sees
284 * an actual problem case.
286 setlocale(LC_MESSAGES, "");
287 string = gettext(string);
288 setlocale(LC_MESSAGES, "C");
289 #endif
290 return string;
293 void mp_tmsg(int mod, int lev, const char *format, ...)
295 va_list va;
296 va_start(va, format);
297 mp_msg_va(mod, lev, mp_gtext(format), va);
298 va_end(va);