filename | src/util.c |
changeset | 1239:be3121267597 |
prev | 1148:8e75fab17be8 |
author | nkeynes |
date | Thu Mar 15 08:26:06 2012 +1000 (12 years ago) |
permissions | -rw-r--r-- |
last change | GDB: Support ^C interruption from GDB - postpone dreamcast_run() until after the IO callback returns (callback won't be called again until the callback returns, so blocks all input) - generate stop notifications when the DC stops, regardless of where the stop originates. |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 *
4 * Miscellaneous utility functions.
5 *
6 * Copyright (c) 2005 Nathan Keynes.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
19 #define HAVE_EXECINFO_H 1
21 #include <assert.h>
22 #include <ctype.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <signal.h>
28 #include <time.h>
29 #include <zlib.h>
30 #include <glib.h>
31 #include <png.h>
32 #include "dream.h"
33 #include "display.h"
34 #include "dreamcast.h"
35 #include "gui.h"
36 #include "sh4/sh4.h"
38 #ifdef __ANDROID__
39 #include <android/log.h>
40 static int android_log_levels[] = {ANDROID_LOG_FATAL, ANDROID_LOG_ERROR, ANDROID_LOG_WARN, ANDROID_LOG_INFO, ANDROID_LOG_DEBUG, ANDROID_LOG_VERBOSE};
41 #endif
43 char *msg_levels[] = { "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE" };
44 int global_msg_level = EMIT_WARN;
46 static void report_crash( int signo, siginfo_t *info, void *ptr )
47 {
48 char buf[128];
50 fprintf( stderr, "--- Aborting with signal %d ---\n", signo );
51 sh4_crashdump();
52 // Get gdb to print a nice backtrace for us
53 #ifdef APPLE_BUILD
54 snprintf( buf, 128, "echo bt | gdb --quiet --pid=%d", getpid() );
55 #else
56 snprintf( buf, 128, "gdb -batch -f --quiet --pid=%d -ex bt", getpid() );
57 #endif
58 system(buf);
60 abort();
61 }
63 void install_crash_handler(void)
64 {
65 struct sigaction sa;
67 sa.sa_sigaction = report_crash;
68 sigemptyset(&sa.sa_mask);
69 sa.sa_flags = SA_RESETHAND|SA_SIGINFO;
70 sigaction( SIGSEGV, &sa, NULL );
71 sigaction( SIGILL, &sa, NULL );
72 sigaction( SIGBUS, &sa, NULL );
73 }
76 void fwrite_string( const char *s, FILE *f )
77 {
78 uint32_t len = 0;
79 if( s == NULL ) {
80 fwrite( &len, sizeof(len), 1, f );
81 } else {
82 len = strlen(s)+1;
83 fwrite( &len, sizeof(len), 1, f );
84 fwrite( s, len, 1, f );
85 }
86 }
88 int fread_string( char *s, int maxlen, FILE *f )
89 {
90 uint32_t len;
91 fread( &len, sizeof(len), 1, f );
92 if( len != 0 ) {
93 fread( s, len > maxlen ? maxlen : len, 1, f );
94 }
95 return len;
96 }
98 int fwrite_gzip( void *p, size_t sz, size_t count, FILE *f )
99 {
100 uLongf size = sz*count;
101 uLongf csize = ((int)(size*1.001))+13;
102 unsigned char *tmp = g_malloc0( csize );
103 int status = compress( tmp, &csize, p, size );
104 assert( status == Z_OK );
105 uint32_t wsize = (uint32_t)csize;
106 fwrite( &wsize, sizeof(wsize), 1, f );
107 int written = fwrite( tmp, csize, 1, f );
108 g_free(tmp);
110 /* Could be finer-grained, but this is enough to know it succeeded/failed */
111 if( written == 1 ) {
112 return count;
113 } else {
114 return 0;
115 }
116 }
118 int fread_gzip( void *p, size_t sz, size_t count, FILE *f )
119 {
120 uLongf size = sz*count;
121 uint32_t csize;
122 unsigned char *tmp;
124 fread( &csize, sizeof(csize), 1, f );
125 assert( csize <= (size*2) );
126 tmp = g_malloc0( csize );
127 fread( tmp, csize, 1, f );
128 int status = uncompress( p, &size, tmp, csize );
129 g_free(tmp);
130 if( status == Z_OK ) {
131 return count;
132 } else {
133 fprintf( stderr, "Error reading compressed data\n" );
134 return 0;
135 }
136 }
138 void fwrite_dump( unsigned char *data, unsigned int length, FILE *f )
139 {
140 unsigned int i, j;
141 for( i =0; i<length; i+=16 ) {
142 fprintf( f, "%08X:", i);
143 for( j=i; j<i+16; j++ ) {
144 if( (j % 4) == 0 )
145 fprintf( f, " " );
146 if( j < length )
147 fprintf( f, " %02X", (unsigned int)(data[j]) );
148 else
149 fprintf( f, " " );
150 }
151 fprintf( f, " " );
152 for( j=i; j<i+16 && j<length; j++ ) {
153 fprintf( f, "%c", isprint(data[j]) ? data[j] : '.' );
154 }
155 fprintf( f, "\n" );
156 }
157 }
159 void fwrite_dump32( unsigned int *data, unsigned int length, FILE *f )
160 {
161 fwrite_dump32v( data, length, 8, f );
162 }
164 void fwrite_dump32v( unsigned int *data, unsigned int length, int wordsPerLine, FILE *f )
165 {
166 unsigned int i, j;
167 for( i =0; i<length>>2; i+=wordsPerLine ) {
168 fprintf( f, "%08X:", i);
169 for( j=i; j<i+wordsPerLine; j++ ) {
170 if( j < length )
171 fprintf( f, " %08X", (unsigned int)(data[j]) );
172 else
173 fprintf( f, " " );
174 }
175 fprintf( f, "\n" );
176 }
177 }
179 gboolean write_png_to_stream( FILE *f, frame_buffer_t buffer )
180 {
181 int coltype, i;
182 png_bytep p;
183 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
184 if (!png_ptr) {
185 return FALSE;
186 }
188 png_infop info_ptr = png_create_info_struct(png_ptr);
189 if (!info_ptr) {
190 png_destroy_write_struct(&png_ptr, NULL);
191 return FALSE;
192 }
194 if( setjmp(png_jmpbuf(png_ptr)) ) {
195 png_destroy_write_struct(&png_ptr, &info_ptr);
196 return FALSE;
197 }
198 png_init_io( png_ptr, f );
199 switch( buffer->colour_format ) {
200 case COLFMT_BGR888:
201 coltype = PNG_COLOR_TYPE_RGB;
202 break;
203 case COLFMT_BGRA8888:
204 coltype = PNG_COLOR_TYPE_RGB_ALPHA;
205 break;
206 case COLFMT_BGR0888:
207 coltype = PNG_COLOR_TYPE_RGB;
208 break;
209 default:
210 coltype = PNG_COLOR_TYPE_RGB;
211 }
212 png_set_IHDR(png_ptr, info_ptr, buffer->width, buffer->height,
213 8, coltype, PNG_INTERLACE_NONE,
214 PNG_COMPRESSION_TYPE_DEFAULT,
215 PNG_FILTER_TYPE_DEFAULT );
216 png_write_info(png_ptr, info_ptr);
217 if( buffer->colour_format == COLFMT_BGR0888 ) {
218 png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
219 }
220 png_set_bgr(png_ptr);
221 if( buffer->inverted ) {
222 p = (png_bytep)(buffer->data + (buffer->height*buffer->rowstride) - buffer->rowstride);
223 for(i=0; i<buffer->height; i++ ) {
224 png_write_row(png_ptr, p);
225 p-=buffer->rowstride;
226 }
227 } else {
228 p = (png_bytep)buffer->data;
229 for(i=0; i<buffer->height; i++ ) {
230 png_write_row(png_ptr, p);
231 p+=buffer->rowstride;
232 }
233 }
234 png_write_end(png_ptr, info_ptr);
235 png_destroy_write_struct(&png_ptr, &info_ptr);
236 return TRUE;
237 }
239 frame_buffer_t read_png_from_stream( FILE *f )
240 {
241 png_bytep p;
242 int i;
243 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
244 NULL, NULL, NULL);
245 if (!png_ptr) {
246 return NULL;
247 }
249 png_infop info_ptr = png_create_info_struct(png_ptr);
250 if (!info_ptr) {
251 png_destroy_read_struct(&png_ptr, NULL, NULL);
252 return NULL;
253 }
255 png_infop end_info = png_create_info_struct(png_ptr);
256 if (!end_info) {
257 png_destroy_read_struct(&png_ptr, &info_ptr, NULL );
258 return NULL;
259 }
261 if( setjmp(png_jmpbuf(png_ptr)) ) {
262 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
263 return NULL;
264 }
266 png_init_io(png_ptr, f);
267 png_read_info(png_ptr, info_ptr);
269 png_uint_32 width, height;
270 int bit_depth, color_type, interlace_type,
271 compression_type, filter_method;
272 png_get_IHDR(png_ptr, info_ptr, &width, &height,
273 &bit_depth, &color_type, &interlace_type,
274 &compression_type, &filter_method);
275 assert( interlace_type == PNG_INTERLACE_NONE );
276 int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
277 int channels = png_get_channels(png_ptr, info_ptr);
278 frame_buffer_t buffer = g_malloc( sizeof(struct frame_buffer) + rowbytes*height );
279 buffer->data = (unsigned char *)(buffer+1);
280 buffer->width = width;
281 buffer->height = height;
282 buffer->rowstride = rowbytes;
283 buffer->address = -1;
284 buffer->size = rowbytes*height;
285 buffer->inverted = FALSE;
286 if( channels == 4 ) {
287 buffer->colour_format = COLFMT_BGRA8888;
288 } else if( channels == 3 ) {
289 buffer->colour_format = COLFMT_RGB888;
290 }
292 p = (png_bytep)buffer->data;
293 for( i=0; i<height; i++ ) {
294 png_read_row(png_ptr, p, NULL );
295 p += rowbytes;
296 }
298 png_read_end(png_ptr, end_info);
299 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
300 return buffer;
301 }
303 int get_log_level_from_string( const gchar *str )
304 {
305 switch( tolower(str[0]) ) {
306 case 'd': return EMIT_DEBUG;
307 case 'e': return EMIT_ERR;
308 case 'f': return EMIT_FATAL;
309 case 'i': return EMIT_INFO;
310 case 't': return EMIT_TRACE;
311 case 'w': return EMIT_WARN;
312 default: return -1;
313 }
314 }
316 gboolean set_global_log_level( const gchar *str )
317 {
318 int l = get_log_level_from_string(str);
319 if( l == -1 ) {
320 return FALSE;
321 } else {
322 global_msg_level = l;
323 return TRUE;
324 }
325 }
327 void log_message( void *ptr, int level, const gchar *source, const char *msg, ... )
328 {
329 char buf[20];
330 time_t tm = time(NULL);
331 va_list ap;
333 if( level > global_msg_level ) {
334 return; // ignored
335 }
337 va_start(ap, msg);
338 gchar *text = g_strdup_vprintf( msg, ap );
339 va_end(ap);
341 if( level <= EMIT_ERR ) {
342 if( gui_error_dialog( text ) ) {
343 g_free(text);
344 // If we're running, halt on error to avoid potentially flooding
345 // the user with error messages.
346 if( dreamcast_is_running() ) {
347 dreamcast_stop();
348 }
349 return;
350 }
351 }
353 strftime( buf, sizeof(buf), "%H:%M:%S", localtime(&tm) );
354 #ifdef __ANDROID__
355 __android_log_print(android_log_levels[level], "lxdream", "%s %08X %s\n", buf, sh4r.pc, text );
356 #else
357 fprintf( stderr, "%s %08X %-5s %s\n", buf, sh4r.pc, msg_levels[level], text );
358 #endif
359 g_free(text);
360 }
.