1 /*
2  * This file is part of MPlayer.
3  *
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.
8  *
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.
13  *
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.
17  */
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stdarg.h>
22 #include <string.h>
23 
24 #include "config.h"
25 #include "libavutil/avstring.h"
26 #include "osdep/getch2.h"
27 
28 #ifdef CONFIG_ICONV
29 #include <iconv.h>
30 #include <errno.h>
31 #endif
32 
33 #include "mp_msg.h"
34 
35 /* maximum message length of mp_msg */
36 #define MSGSIZE_MAX 3072
37 
38 int mp_msg_levels[MSGT_MAX]; // verbose level of this module. initialized to -2
39 int mp_msg_level_all = MSGL_STATUS;
40 int verbose = 0;
41 int mp_msg_color = 0;
42 int mp_msg_module = 0;
43 #ifdef CONFIG_ICONV
44 char *mp_msg_charset = NULL;
45 // only used to simplify freeing get_term_charset
46 // result, even when it was overwritten by command-line options.
47 char *term_charset_ptr_to_free = NULL;
48 static char *old_charset = NULL;
49 static iconv_t msgiconv;
50 static iconv_t inv_msgiconv = (iconv_t)(-1);
51 #endif
52 
filename_recode(const char * filename)53 const char* filename_recode(const char* filename)
54 {
55 #if !defined(CONFIG_ICONV) || !defined(MSG_CHARSET)
56     return filename;
57 #else
58     static char recoded_filename[MSGSIZE_MAX];
59     size_t filename_len, max_path;
60     char* precoded;
61     if (!mp_msg_charset ||
62         !av_strcasecmp(mp_msg_charset, MSG_CHARSET) ||
63         !av_strcasecmp(mp_msg_charset, "noconv"))
64         return filename;
65     if (inv_msgiconv == (iconv_t)(-1)) {
66         inv_msgiconv = iconv_open(MSG_CHARSET, mp_msg_charset);
67         if (inv_msgiconv == (iconv_t)(-1))
68             return filename;
69     }
70     filename_len = strlen(filename);
71     max_path = MSGSIZE_MAX - 4;
72     precoded = recoded_filename;
73     if (iconv(inv_msgiconv, &filename, &filename_len,
74               &precoded, &max_path) == (size_t)(-1) && errno == E2BIG) {
75         precoded[0] = precoded[1] = precoded[2] = '.';
76         precoded += 3;
77     }
78     *precoded = '\0';
79     return recoded_filename;
80 #endif
81 }
82 
mp_msg_init(void)83 void mp_msg_init(void){
84     int i;
85     char *env = getenv("MPLAYER_VERBOSE");
86     if (env)
87         verbose = atoi(env);
88     for(i=0;i<MSGT_MAX;i++) mp_msg_levels[i] = -2;
89     mp_msg_levels[MSGT_IDENTIFY] = -1; // no -identify output by default
90 #ifdef CONFIG_ICONV
91     mp_msg_charset = getenv("MPLAYER_CHARSET");
92     if (!mp_msg_charset) {
93       free(term_charset_ptr_to_free); // could assert that is is NULL instead
94       mp_msg_charset = term_charset_ptr_to_free = get_term_charset();
95     }
96 #endif
97 }
98 
mp_msg_uninit(void)99 void mp_msg_uninit(void)
100 {
101 #ifdef CONFIG_ICONV
102     if (old_charset) {
103         free(old_charset);
104         iconv_close(msgiconv);
105     }
106     if (inv_msgiconv != (iconv_t)(-1)) iconv_close(inv_msgiconv);
107     free(term_charset_ptr_to_free);
108     term_charset_ptr_to_free = NULL;
109 #endif
110 }
111 
mp_msg_test(int mod,int lev)112 int mp_msg_test(int mod, int lev)
113 {
114     return lev <= (mp_msg_levels[mod] == -2 ? mp_msg_level_all + verbose : mp_msg_levels[mod]);
115 }
116 
set_msg_color(FILE * stream,int lev)117 static void set_msg_color(FILE* stream, int lev)
118 {
119     static const unsigned char v_colors[10] = {9, 1, 3, 15, 7, 2, 2, 8, 8, 8};
120     int c = v_colors[lev];
121 #ifdef MP_ANNOY_ME
122     /* that's only a silly color test */
123     {
124         int c;
125         static int flag = 1;
126         if (flag)
127             for(c = 0; c < 24; c++)
128                 printf("\033[%d;3%dm***  COLOR TEST %d  ***\n", c>7, c&7, c);
129         flag = 0;
130     }
131 #endif
132     if (mp_msg_color)
133         fprintf(stream, "\033[%d;3%dm", c >> 3, c & 7);
134 }
135 
print_msg_module(FILE * stream,int mod)136 static void print_msg_module(FILE* stream, int mod)
137 {
138     static const char *module_text[MSGT_MAX] = {
139         "GLOBAL",
140         "CPLAYER",
141         "GPLAYER",
142         "VIDEOOUT",
143         "AUDIOOUT",
144         "DEMUXER",
145         "DS",
146         "DEMUX",
147         "HEADER",
148         "AVSYNC",
149         "AUTOQ",
150         "CFGPARSER",
151         "DECAUDIO",
152         "DECVIDEO",
153         "SEEK",
154         "WIN32",
155         "OPEN",
156         "DVD",
157         "PARSEES",
158         "LIRC",
159         "STREAM",
160         "CACHE",
161         "MENCODER",
162         "XACODEC",
163         "TV",
164         "OSDEP",
165         "SPUDEC",
166         "PLAYTREE",
167         "INPUT",
168         "VFILTER",
169         "OSD",
170         "NETWORK",
171         "CPUDETECT",
172         "CODECCFG",
173         "SWS",
174         "VOBSUB",
175         "SUBREADER",
176         "AFILTER",
177         "NETST",
178         "MUXER",
179         "OSDMENU",
180         "IDENTIFY",
181         "RADIO",
182         "ASS",
183         "LOADER",
184         "STATUSLINE",
185     };
186     int c2 = (mod + 1) % 15 + 1;
187 
188     if (!mp_msg_module)
189         return;
190     if (mp_msg_color)
191         fprintf(stream, "\033[%d;3%dm", c2 >> 3, c2 & 7);
192     fprintf(stream, "%9s", module_text[mod]);
193     if (mp_msg_color)
194         fprintf(stream, "\033[0;37m");
195     fprintf(stream, ": ");
196 }
197 
mp_msg(int mod,int lev,const char * format,...)198 void mp_msg(int mod, int lev, const char *format, ... ){
199     va_list va;
200     va_start(va, format);
201     mp_msg_va(mod, lev, format, va);
202     va_end(va);
203 }
204 
mp_msg_va(int mod,int lev,const char * format,va_list va)205 void mp_msg_va(int mod, int lev, const char *format, va_list va){
206     char tmp[MSGSIZE_MAX];
207     FILE *stream = lev <= MSGL_WARN ? stderr : stdout;
208     static int header = 1;
209     // indicates if last line printed was a status line
210     static int statusline;
211     size_t len;
212 
213     if (!mp_msg_test(mod, lev)) return; // do not display
214     vsnprintf(tmp, MSGSIZE_MAX, format, va);
215     tmp[MSGSIZE_MAX-2] = '\n';
216     tmp[MSGSIZE_MAX-1] = 0;
217 
218 #if defined(CONFIG_ICONV) && defined(MSG_CHARSET)
219     if (mp_msg_charset && av_strcasecmp(mp_msg_charset, "noconv")) {
220       char tmp2[MSGSIZE_MAX];
221       size_t inlen = strlen(tmp), outlen = MSGSIZE_MAX;
222       char *in = tmp, *out = tmp2;
223       if (!old_charset || strcmp(old_charset, mp_msg_charset)) {
224         if (old_charset) {
225           free(old_charset);
226           iconv_close(msgiconv);
227         }
228         msgiconv = iconv_open(mp_msg_charset, MSG_CHARSET);
229         old_charset = strdup(mp_msg_charset);
230       }
231       if (msgiconv == (iconv_t)(-1)) {
232         fprintf(stderr,"iconv: conversion from %s to %s unsupported\n"
233                ,MSG_CHARSET,mp_msg_charset);
234       }else{
235       memset(tmp2, 0, MSGSIZE_MAX);
236       while (iconv(msgiconv, &in, &inlen, &out, &outlen) == -1) {
237         if (!inlen || !outlen)
238           break;
239         *out++ = *in++;
240         outlen--; inlen--;
241       }
242       strncpy(tmp, tmp2, MSGSIZE_MAX);
243       tmp[MSGSIZE_MAX-1] = 0;
244       tmp[MSGSIZE_MAX-2] = '\n';
245       }
246     }
247 #endif
248 
249     // as a status line normally is intended to be overwitten by next status line
250     // output a '\n' to get a normal message on a separate line
251     if (statusline && lev != MSGL_STATUS) fprintf(stream, "\n");
252     statusline = lev == MSGL_STATUS;
253 
254     if (header)
255         print_msg_module(stream, mod);
256     set_msg_color(stream, lev);
257     len = strlen(tmp);
258     header = len && (tmp[len-1] == '\n' || tmp[len-1] == '\r');
259 
260     fprintf(stream, "%s", tmp);
261     if (mp_msg_color)
262         fprintf(stream, "\033[0m");
263     fflush(stream);
264 }
265