1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #ifdef STDC_HEADERS
6 # include <stdlib.h>
7 # include <string.h>
8 #else
9 # ifndef HAVE_STRCHR
10 # define strchr index
11 # define strrchr rindex
12 # endif
13 char *strchr(), *strrchr();
14 # ifndef HAVE_MEMCPY
15 # define memcpy(d, s, n) bcopy ((s), (d), (n))
16 # define memmove(d, s, n) bcopy ((s), (d), (n))
17 # endif
18 #endif
19
20 #if defined(HAVE_NCURSES_TERMCAP_H)
21 # include <ncurses/termcap.h>
22 #elif defined(HAVE_TERMCAP_H)
23 # include <termcap.h>
24 #elif defined(HAVE_TERMCAP)
25 # include <curses.h>
26 # if !defined(__bsdi__)
27 # include <term.h>
28 # endif
29 #endif
30
31 #include <stdio.h>
32 #include <stdarg.h>
33 #include "console.h"
34 #include "main.h"
35
36 #ifdef WITH_DMALLOC
37 #include <dmalloc.h>
38 #endif
39
40 #define CLASS_ID 0x434F4E53
41 #define REPORT_BUFF_SIZE 1024
42
43 #if defined(_WIN32) && !defined(__CYGWIN__)
44 # include <windows.h>
45 #endif
46
47
48 /*
49 * Taken from Termcap_Manual.html:
50 *
51 * With the Unix version of termcap, you must allocate space for the description yourself and pass
52 * the address of the space as the argument buffer. There is no way you can tell how much space is
53 * needed, so the convention is to allocate a buffer 2048 characters long and assume that is
54 * enough. (Formerly the convention was to allocate 1024 characters and assume that was enough.
55 * But one day, for one kind of terminal, that was not enough.)
56 */
57
58 #ifdef HAVE_TERMCAP
59
60 static void
get_termcap_string(char const * id,char * dest,size_t n)61 get_termcap_string(char const* id, char* dest, size_t n)
62 {
63 char tc[16];
64 char *tp = tc;
65 tp[0] = '\0';
66 tp = tgetstr(id, &tp);
67 if (tp != NULL && dest != NULL && n > 0) {
68 strncpy(dest, tp, n);
69 dest[n-1] = '\0';
70 }
71 }
72
73 static void
get_termcap_number(char const * id,int * dest,int low,int high)74 get_termcap_number(char const* id, int* dest, int low, int high)
75 {
76 int const val = tgetnum(id);
77 if (low <= val && val <= high) {
78 *dest = val;
79 }
80 }
81
82 static void
apply_termcap_settings(Console_IO_t * const mfp)83 apply_termcap_settings(Console_IO_t * const mfp)
84 {
85 /* try to catch additional information about special console sequences */
86 char const* term_name = getenv("TERM");
87 if (NULL != term_name) {
88 char term_buff[4096];
89 int const ret = tgetent(term_buff, term_name);
90 if (1 == ret) {
91 get_termcap_number("co", &mfp->disp_width, 40, 512);
92 get_termcap_number("li", &mfp->disp_height, 16, 256);
93 get_termcap_string("up", mfp->str_up, sizeof(mfp->str_up));
94 get_termcap_string("md", mfp->str_emph, sizeof(mfp->str_emph));
95 get_termcap_string("me", mfp->str_norm, sizeof(mfp->str_norm));
96 get_termcap_string("ce", mfp->str_clreoln, sizeof(mfp->str_clreoln));
97 }
98 }
99 }
100 #endif /* TERMCAP_AVAILABLE */
101
102 static int
is_console_initialized(Console_IO_t * const mfp)103 is_console_initialized(Console_IO_t * const mfp)
104 {
105 return mfp && mfp->ClassID == CLASS_ID ? 1 : 0;
106 }
107
108 static int
init_console(Console_IO_t * const mfp)109 init_console(Console_IO_t * const mfp)
110 {
111 if (is_console_initialized(mfp)) {
112 return 0; /* already initialized */
113 }
114 /* setup basics of brhist I/O channels */
115 mfp->disp_width = 80;
116 mfp->disp_height = 25;
117 mfp->Console_fp = stderr;
118 mfp->Error_fp = stderr;
119 mfp->Report_fp = NULL;
120
121 /*mfp -> Console_buff = calloc ( 1, REPORT_BUFF_SIZE ); */
122 setvbuf(mfp->Console_fp, mfp->Console_buff, _IOFBF, sizeof(mfp->Console_buff));
123 /* setvbuf ( mfp -> Error_fp , NULL , _IONBF, 0 ); */
124
125 #if defined(_WIN32) && !defined(__CYGWIN__)
126 mfp->Console_Handle = GetStdHandle(STD_ERROR_HANDLE);
127 #endif
128
129 strcpy(mfp->str_up, "\033[A");
130
131 #ifdef HAVE_TERMCAP
132 apply_termcap_settings(mfp);
133 #endif /* TERMCAP_AVAILABLE */
134
135 mfp->ClassID = CLASS_ID;
136
137 #if defined(_WIN32) && !defined(__CYGWIN__)
138 mfp->Console_file_type = GetFileType(Console_IO.Console_Handle);
139 #else
140 mfp->Console_file_type = 0;
141 #endif
142 return 0;
143 }
144
145 static void
deinit_console(Console_IO_t * const mfp)146 deinit_console(Console_IO_t * const mfp)
147 {
148 if (!is_console_initialized(mfp)) {
149 return; /* not initialized or already de-initialized */
150 }
151 if (mfp->Report_fp != NULL) {
152 fclose(mfp->Report_fp);
153 mfp->Report_fp = NULL;
154 }
155 fflush(mfp->Console_fp);
156 setvbuf(mfp->Console_fp, NULL, _IONBF, (size_t) 0);
157
158 memset(mfp->Console_buff, 0x55, REPORT_BUFF_SIZE);
159 }
160
161 /* LAME console
162 */
163 Console_IO_t Console_IO;
164
165 enum ConsoleEnum { ConsoleIoConsole, ConsoleIoError, ConsoleIoReport };
166
167 static FILE*
frontend_console_file_handle(enum ConsoleEnum e)168 frontend_console_file_handle(enum ConsoleEnum e)
169 {
170 if (is_console_initialized(&Console_IO)) {
171 switch (e) {
172 case ConsoleIoConsole: return Console_IO.Console_fp;
173 case ConsoleIoError: return Console_IO.Error_fp;
174 case ConsoleIoReport: return Console_IO.Report_fp;
175 }
176 }
177 return 0;
178 }
179
180 static int
frontend_console_print(const char * format,va_list ap,enum ConsoleEnum e)181 frontend_console_print(const char *format, va_list ap, enum ConsoleEnum e)
182 {
183 FILE *fp = frontend_console_file_handle(e);
184
185 if (fp != NULL)
186 return vfprintf(fp, format, ap);
187 return 0;
188 }
189
190 static void
frontend_console_flush(enum ConsoleEnum e)191 frontend_console_flush(enum ConsoleEnum e)
192 {
193 FILE *fp = frontend_console_file_handle(e);
194
195 if (fp != NULL)
196 fflush(fp);
197 }
198
199 int
frontend_open_console(void)200 frontend_open_console(void)
201 {
202 return init_console(&Console_IO);
203 }
204
205 void
frontend_close_console(void)206 frontend_close_console(void)
207 {
208 deinit_console(&Console_IO);
209 }
210
211 void
frontend_debugf(const char * format,va_list ap)212 frontend_debugf(const char *format, va_list ap)
213 {
214 (void) frontend_console_print(format, ap, ConsoleIoReport);
215 }
216
217 void
frontend_msgf(const char * format,va_list ap)218 frontend_msgf(const char *format, va_list ap)
219 {
220 (void) frontend_console_print(format, ap, ConsoleIoConsole);
221 }
222
223 void
frontend_errorf(const char * format,va_list ap)224 frontend_errorf(const char *format, va_list ap)
225 {
226 (void) frontend_console_print(format, ap, ConsoleIoError);
227 }
228
229 void
frontend_print_null(const char * format,va_list ap)230 frontend_print_null(const char *format, va_list ap)
231 {
232 (void) format;
233 (void) ap;
234 }
235
236 int
console_printf(const char * format,...)237 console_printf(const char *format, ...)
238 {
239 va_list args;
240 int ret;
241
242 va_start(args, format);
243 ret = frontend_console_print(format, args,ConsoleIoConsole);
244 va_end(args);
245
246 return ret;
247 }
248
249 int
error_printf(const char * format,...)250 error_printf(const char *format, ...)
251 {
252 va_list args;
253 int ret;
254
255 va_start(args, format);
256 ret = frontend_console_print(format, args, ConsoleIoError);
257 va_end(args);
258
259 return ret;
260 }
261
262 int
report_printf(const char * format,...)263 report_printf(const char *format, ...)
264 {
265 va_list args;
266 int ret;
267
268 va_start(args, format);
269 ret = frontend_console_print(format, args, ConsoleIoReport);
270 va_end(args);
271
272 return ret;
273 }
274
275 void
console_flush()276 console_flush()
277 {
278 frontend_console_flush(ConsoleIoConsole);
279 }
280
281 void
error_flush()282 error_flush()
283 {
284 frontend_console_flush(ConsoleIoError);
285 }
286
287 void
report_flush()288 report_flush()
289 {
290 frontend_console_flush(ConsoleIoReport);
291 }
292
293 void
console_up(int n_lines)294 console_up(int n_lines)
295 {
296 if (!is_console_initialized(&Console_IO))
297 return; /* not initialized or already de-initialized */
298 #if defined(_WIN32) && !defined(__CYGWIN__)
299 if (Console_IO.Console_file_type != FILE_TYPE_PIPE) {
300 COORD Pos;
301 CONSOLE_SCREEN_BUFFER_INFO CSBI;
302
303 console_flush();
304 GetConsoleScreenBufferInfo(Console_IO.Console_Handle, &CSBI);
305 Pos.Y = (SHORT)(CSBI.dwCursorPosition.Y - n_lines);
306 Pos.X = 0;
307 SetConsoleCursorPosition(Console_IO.Console_Handle, Pos);
308 }
309 #else
310 while (n_lines-- > 0)
311 fputs(Console_IO.str_up, Console_IO.Console_fp);
312 console_flush();
313 #endif
314 }
315
316 int
console_getwidth()317 console_getwidth()
318 {
319 if (is_console_initialized(&Console_IO))
320 return Console_IO.disp_width;
321 return 80; /* default value */
322 }
323
324 void
set_debug_file(const char * fn)325 set_debug_file(const char *fn)
326 {
327 if (is_console_initialized(&Console_IO)) {
328 if (Console_IO.Report_fp == NULL) {
329 Console_IO.Report_fp = lame_fopen(fn, "a");
330 if (Console_IO.Report_fp != NULL) {
331 error_printf("writing debug info into: %s\n", fn);
332 }
333 else {
334 error_printf("Error: can't open for debug info: %s\n", fn);
335 }
336 }
337 }
338 }
339
340 /* end of console.c */
341