m_config.c: cosmetics: Move functions to avoid forward declarations
[mplayer.git] / mp_msg.c
blobcff4decb7504be90e519f6ffa0d5b298d077ae85
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"
27 #ifdef CONFIG_TRANSLATION
28 #include <locale.h>
29 #include <libintl.h>
30 #endif
32 #ifdef CONFIG_ICONV
33 #include <iconv.h>
34 #include <errno.h>
35 #endif
37 #include "mp_msg.h"
39 /* maximum message length of mp_msg */
40 #define MSGSIZE_MAX 3072
42 int mp_msg_levels[MSGT_MAX]; // verbose level of this module. initialized to -2
43 int mp_msg_level_all = MSGL_STATUS;
44 int verbose = 0;
45 int mp_msg_color = 0;
46 int mp_msg_module = 0;
47 #ifdef CONFIG_ICONV
48 char *mp_msg_charset = NULL;
49 static char *old_charset = NULL;
50 static iconv_t msgiconv;
51 #endif
53 const char* filename_recode(const char* filename)
55 #if !defined(CONFIG_ICONV) || !defined(MSG_CHARSET)
56 return filename;
57 #else
58 static iconv_t inv_msgiconv = (iconv_t)(-1);
59 static char recoded_filename[MSGSIZE_MAX];
60 size_t filename_len, max_path;
61 char* precoded;
62 if (!mp_msg_charset ||
63 !strcasecmp(mp_msg_charset, MSG_CHARSET) ||
64 !strcasecmp(mp_msg_charset, "noconv"))
65 return filename;
66 if (inv_msgiconv == (iconv_t)(-1)) {
67 inv_msgiconv = iconv_open(MSG_CHARSET, mp_msg_charset);
68 if (inv_msgiconv == (iconv_t)(-1))
69 return filename;
71 filename_len = strlen(filename);
72 max_path = MSGSIZE_MAX - 4;
73 precoded = recoded_filename;
74 if (iconv(inv_msgiconv, &filename, &filename_len,
75 &precoded, &max_path) == (size_t)(-1) && errno == E2BIG) {
76 precoded[0] = precoded[1] = precoded[2] = '.';
77 precoded += 3;
79 *precoded = '\0';
80 return recoded_filename;
81 #endif
84 void mp_msg_init(void){
85 int i;
86 char *env = getenv("MPLAYER_VERBOSE");
87 if (env)
88 verbose = atoi(env);
89 for(i=0;i<MSGT_MAX;i++) mp_msg_levels[i] = -2;
90 mp_msg_levels[MSGT_IDENTIFY] = -1; // no -identify output by default
91 #ifdef CONFIG_ICONV
92 mp_msg_charset = getenv("MPLAYER_CHARSET");
93 if (!mp_msg_charset)
94 mp_msg_charset = get_term_charset();
95 #endif
96 #ifdef CONFIG_TRANSLATION
97 textdomain("mplayer");
98 char *localedir = getenv("MPLAYER_LOCALEDIR");
99 if (localedir == NULL && strlen(MPLAYER_LOCALEDIR))
100 localedir = MPLAYER_LOCALEDIR;
101 bindtextdomain("mplayer", localedir);
102 bind_textdomain_codeset("mplayer", "UTF-8");
103 #endif
106 int mp_msg_test(int mod, int lev)
108 return lev <= (mp_msg_levels[mod] == -2 ? mp_msg_level_all + verbose : mp_msg_levels[mod]);
111 static void set_msg_color(FILE* stream, int lev)
113 static const unsigned char v_colors[10] = {9, 1, 3, 15, 7, 2, 2, 8, 8, 8};
114 int c = v_colors[lev];
115 #ifdef MP_ANNOY_ME
116 /* that's only a silly color test */
118 int c;
119 static int flag = 1;
120 if (flag)
121 for(c = 0; c < 24; c++)
122 printf("\033[%d;3%dm*** COLOR TEST %d ***\n", c>7, c&7, c);
123 flag = 0;
125 #endif
126 if (mp_msg_color)
127 fprintf(stream, "\033[%d;3%dm", c >> 3, c & 7);
130 static void print_msg_module(FILE* stream, int mod)
132 static const char *module_text[MSGT_MAX] = {
133 "GLOBAL",
134 "CPLAYER",
135 "GPLAYER",
136 "VIDEOOUT",
137 "AUDIOOUT",
138 "DEMUXER",
139 "DS",
140 "DEMUX",
141 "HEADER",
142 "AVSYNC",
143 "AUTOQ",
144 "CFGPARSER",
145 "DECAUDIO",
146 "DECVIDEO",
147 "SEEK",
148 "WIN32",
149 "OPEN",
150 "DVD",
151 "PARSEES",
152 "LIRC",
153 "STREAM",
154 "CACHE",
155 "MENCODER",
156 "XACODEC",
157 "TV",
158 "OSDEP",
159 "SPUDEC",
160 "PLAYTREE",
161 "INPUT",
162 "VFILTER",
163 "OSD",
164 "NETWORK",
165 "CPUDETECT",
166 "CODECCFG",
167 "SWS",
168 "VOBSUB",
169 "SUBREADER",
170 "AFILTER",
171 "NETST",
172 "MUXER",
173 "OSDMENU",
174 "IDENTIFY",
175 "RADIO",
176 "ASS",
177 "LOADER",
178 "STATUSLINE",
180 int c2 = (mod + 1) % 15 + 1;
182 if (!mp_msg_module)
183 return;
184 if (mp_msg_color)
185 fprintf(stream, "\033[%d;3%dm", c2 >> 3, c2 & 7);
186 fprintf(stream, "%9s", module_text[mod]);
187 if (mp_msg_color)
188 fprintf(stream, "\033[0;37m");
189 fprintf(stream, ": ");
192 void mp_msg_va(int mod, int lev, const char *format, va_list va)
194 char tmp[MSGSIZE_MAX];
195 FILE *stream = lev <= MSGL_WARN ? stderr : stdout;
196 static int header = 1;
197 // indicates if last line printed was a status line
198 static int statusline;
200 if (!mp_msg_test(mod, lev)) return; // do not display
201 vsnprintf(tmp, MSGSIZE_MAX, format, va);
202 tmp[MSGSIZE_MAX-2] = '\n';
203 tmp[MSGSIZE_MAX-1] = 0;
205 #if defined(CONFIG_ICONV) && defined(MSG_CHARSET)
206 if (mp_msg_charset && strcasecmp(mp_msg_charset, "noconv")) {
207 char tmp2[MSGSIZE_MAX];
208 size_t inlen = strlen(tmp), outlen = MSGSIZE_MAX;
209 char *in = tmp, *out = tmp2;
210 if (!old_charset || strcmp(old_charset, mp_msg_charset)) {
211 if (old_charset) {
212 free(old_charset);
213 iconv_close(msgiconv);
215 msgiconv = iconv_open(mp_msg_charset, MSG_CHARSET);
216 old_charset = strdup(mp_msg_charset);
218 if (msgiconv == (iconv_t)(-1)) {
219 fprintf(stderr,"iconv: conversion from %s to %s unsupported\n"
220 ,MSG_CHARSET,mp_msg_charset);
221 }else{
222 memset(tmp2, 0, MSGSIZE_MAX);
223 while (iconv(msgiconv, &in, &inlen, &out, &outlen) == -1) {
224 if (!inlen || !outlen)
225 break;
226 *out++ = *in++;
227 outlen--; inlen--;
229 strncpy(tmp, tmp2, MSGSIZE_MAX);
230 tmp[MSGSIZE_MAX-1] = 0;
231 tmp[MSGSIZE_MAX-2] = '\n';
234 #endif
236 /* A status line is normally intended to be overwritten by the next
237 * status line, and does not end with a '\n'. If we're printing a normal
238 * line instead after the status one print '\n' to change line. */
239 if (statusline && lev != MSGL_STATUS)
240 fprintf(stream, "\n");
241 statusline = lev == MSGL_STATUS;
243 if (header)
244 print_msg_module(stream, mod);
245 set_msg_color(stream, lev);
247 size_t len = strlen(tmp);
248 header = len && (tmp[len-1] == '\n' || tmp[len-1] == '\r');
250 fprintf(stream, "%s", tmp);
251 if (mp_msg_color)
252 fprintf(stream, "\033[0m");
253 fflush(stream);
256 void mp_msg(int mod, int lev, const char *format, ...)
258 va_list va;
259 va_start(va, format);
260 mp_msg_va(mod, lev, format, va);
261 va_end(va);
264 char *mp_gtext(const char *string)
266 #ifdef CONFIG_TRANSLATION
267 /* gettext expects the global locale to be set with
268 * setlocale(LC_ALL, ""). However doing that would suck for a
269 * couple of reasons (locale stuff is badly designed and sucks in
270 * general).
272 * First setting the locale, especially LC_CTYPE, changes the
273 * behavior of various C functions and we don't want that - we
274 * want isalpha() for example to always behave like in the C
275 * locale.
277 * Second, there is no way to enforce a sane character set. All
278 * strings inside MPlayer must always be in utf-8, not in the
279 * character set specified by the system locale which could be
280 * something different and completely insane. The locale system
281 * lacks any way to say "set LC_CTYPE to utf-8, ignoring the
282 * default system locale if it specifies something different". We
283 * could try to work around that flaw by leaving LC_CTYPE to the C
284 * locale and only setting LC_MESSAGES (which is the variable that
285 * must be set to tell gettext which language to translate
286 * to). However if we leave LC_MESSAGES set then things like
287 * strerror() may produce completely garbled output when they try
288 * to translate their results but then try to convert some
289 * translated non-ASCII text to the character set specified by
290 * LC_CTYPE which would still be in the C locale (this doesn't
291 * affect gettext itself because it supports specifying the
292 * character set directly with bind_textdomain_codeset()).
294 * So the only solution (at leat short of trying to work around
295 * things possibly producing non-utf-8 output) is to leave all the
296 * locale variables unset. Note that this means it's not possible
297 * to get translated output from any libraries we call if they
298 * only rely on the broken locale system to specify the language
299 * to use; this is the case with libc for example.
301 * The locale changing below is rather ugly, but hard to avoid.
302 * gettext doesn't support specifying the translation target
303 * directly, only through locale.
304 * The main actual problem this could cause is interference with
305 * other threads; that could be avoided with thread-specific
306 * locale changes, but such functionality is less standard and I
307 * think it's not worth adding pre-emptively unless someone sees
308 * an actual problem case.
310 setlocale(LC_MESSAGES, "");
311 string = gettext(string);
312 setlocale(LC_MESSAGES, "C");
313 #endif
314 return string;
317 void mp_tmsg(int mod, int lev, const char *format, ...)
319 va_list va;
320 va_start(va, format);
321 mp_msg_va(mod, lev, mp_gtext(format), va);
322 va_end(va);