From: <fr...@us...> - 2011-08-11 12:59:55
|
Revision: 4534 http://fuse-emulator.svn.sourceforge.net/fuse-emulator/?rev=4534&view=rev Author: fredm Date: 2011-08-11 12:59:47 +0000 (Thu, 11 Aug 2011) Log Message: ----------- Add support for POK files (patch #3382538) (Sergio Baldov?\195?\173). Modified Paths: -------------- trunk/fuse/compat/unix/file.c trunk/fuse/compat.h trunk/fuse/fuse.c trunk/fuse/hacking/ChangeLog trunk/fuse/machine.c trunk/fuse/menu.h trunk/fuse/menu_data.dat trunk/fuse/pokefinder/Makefile.am trunk/fuse/ui/fb/fbui.c trunk/fuse/ui/gtk/Makefile.am trunk/fuse/ui/sdl/sdlui.c trunk/fuse/ui/svga/svgaui.c trunk/fuse/ui/ui.h trunk/fuse/ui/win32/win32ui.c trunk/fuse/utils.c trunk/libspectrum/hacking/ChangeLog trunk/libspectrum/libspectrum.c trunk/libspectrum/libspectrum.h.in Added Paths: ----------- trunk/fuse/pokefinder/pokemem.c trunk/fuse/pokefinder/pokemem.h trunk/fuse/ui/gtk/pokemem.c Modified: trunk/fuse/compat/unix/file.c =================================================================== --- trunk/fuse/compat/unix/file.c 2011-08-08 12:44:34 UTC (rev 4533) +++ trunk/fuse/compat/unix/file.c 2011-08-11 12:59:47 UTC (rev 4534) @@ -90,3 +90,9 @@ { return fclose( fd ); } + +int +compat_file_exists( const char *path ) +{ + return ( access( path, R_OK ) != -1 ); +} Modified: trunk/fuse/compat.h =================================================================== --- trunk/fuse/compat.h 2011-08-08 12:44:34 UTC (rev 4533) +++ trunk/fuse/compat.h 2011-08-11 12:59:47 UTC (rev 4534) @@ -96,6 +96,7 @@ int compat_file_write( compat_fd fd, const unsigned char *buffer, size_t length ); int compat_file_close( compat_fd fd ); +int compat_file_exists( const char *path ); /* Directory handling */ Modified: trunk/fuse/fuse.c =================================================================== --- trunk/fuse/fuse.c 2011-08-08 12:44:34 UTC (rev 4533) +++ trunk/fuse/fuse.c 2011-08-11 12:59:47 UTC (rev 4534) @@ -78,6 +78,7 @@ #include "peripherals/speccyboot.h" #include "peripherals/ula.h" #include "pokefinder/pokefinder.h" +#include "pokefinder/pokemem.h" #include "profile.h" #include "psg.h" #include "rzx.h" @@ -632,6 +633,12 @@ case LIBSPECTRUM_CLASS_TAPE: start_files->tape = filename; break; + case LIBSPECTRUM_CLASS_AUXILIARY: + if( type == LIBSPECTRUM_ID_AUX_POK ) { + pokemem_set_pokfile( filename ); + } + break; + case LIBSPECTRUM_CLASS_UNKNOWN: ui_error( UI_ERROR_WARNING, "couldn't identify '%s'; ignoring it", filename ); @@ -843,6 +850,7 @@ event_end(); fuse_joystick_end(); ui_end(); + pokemem_end(); libspectrum_creator_free( fuse_creator ); Modified: trunk/fuse/hacking/ChangeLog =================================================================== --- trunk/fuse/hacking/ChangeLog 2011-08-08 12:44:34 UTC (rev 4533) +++ trunk/fuse/hacking/ChangeLog 2011-08-11 12:59:47 UTC (rev 4534) @@ -3655,3 +3655,8 @@ machines/machines_periph.h is not packed in the tarball, ui/widget/options_internals.h is not removed with distclean, and ui/widget/options.h no longer exists (patch #3388283) (Sergio Baldoví). +20110811 compat.h,compat/unix/file.c,fuse.c,machine.c,menu.h,menu_data.dat, + pokefinder/{Makefile.am,pokemem.[ch]},ui/fb/fbui.c, + ui/gtk/{Makefile.am,pokemem.c},ui/sdl/sdlui.c,ui/svga/svgaui.c, + ui/ui.h,ui/win32/win32ui.c,utils.c: add support for POK files + (patch #3382538) (Sergio Baldoví). Modified: trunk/fuse/machine.c =================================================================== --- trunk/fuse/machine.c 2011-08-08 12:44:34 UTC (rev 4533) +++ trunk/fuse/machine.c 2011-08-11 12:59:47 UTC (rev 4534) @@ -40,6 +40,7 @@ #include "memory.h" #include "module.h" #include "peripherals/ula.h" +#include "pokefinder/pokemem.h" #include "settings.h" #include "snapshot.h" #include "sound.h" @@ -384,6 +385,9 @@ /* clear out old display image ready for new one */ display_refresh_all(); + /* Clear poke list */ + pokemem_clear(); + return 0; } Modified: trunk/fuse/menu.h =================================================================== --- trunk/fuse/menu.h 2011-08-08 12:44:34 UTC (rev 4533) +++ trunk/fuse/menu.h 2011-08-11 12:59:47 UTC (rev 4534) @@ -155,6 +155,7 @@ MENU_DETAIL( menu_machine_detail ); MENU_CALLBACK( menu_machine_debugger ); MENU_CALLBACK( menu_machine_pokefinder ); +MENU_CALLBACK( menu_machine_pokememory ); MENU_CALLBACK( menu_machine_memorybrowser ); MENU_CALLBACK( menu_help_keyboard ); Modified: trunk/fuse/menu_data.dat =================================================================== --- trunk/fuse/menu_data.dat 2011-08-08 12:44:34 UTC (rev 4533) +++ trunk/fuse/menu_data.dat 2011-08-11 12:59:47 UTC (rev 4534) @@ -118,6 +118,9 @@ Machine/_Select..., Item, F9,, menu_machine_detail Machine/_Debugger..., Item Machine/P_oke Finder..., Item +#ifdef UI_GTK +Machine/Po_ke Memory..., Item +#endif Machine/_Memory Browser..., Item Machine/Pro_filer, Branch Modified: trunk/fuse/pokefinder/Makefile.am =================================================================== --- trunk/fuse/pokefinder/Makefile.am 2011-08-08 12:44:34 UTC (rev 4533) +++ trunk/fuse/pokefinder/Makefile.am 2011-08-11 12:59:47 UTC (rev 4534) @@ -27,8 +27,10 @@ noinst_LIBRARIES = libpokefinder.a -libpokefinder_a_SOURCES = pokefinder.c +libpokefinder_a_SOURCES = pokefinder.c \ + pokemem.c -noinst_HEADERS = pokefinder.h +noinst_HEADERS = pokefinder.h \ + pokemem.h -INCLUDES = @LIBSPEC_CFLAGS@ +INCLUDES = @GLIB_CFLAGS@ @GTK_CFLAGS@ @LIBSPEC_CFLAGS@ Added: trunk/fuse/pokefinder/pokemem.c =================================================================== --- trunk/fuse/pokefinder/pokemem.c (rev 0) +++ trunk/fuse/pokefinder/pokemem.c 2011-08-11 12:59:47 UTC (rev 4534) @@ -0,0 +1,579 @@ +/* pokemem.c: help with handling pokes + Copyright (c) 2011 Philip Kendall, Sergio Baldoví + + $Id$ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + Author contact information: + + E-mail: phi...@sh... + +*/ +#include <string.h> + +#include "compat.h" +#include "machine.h" +#include "memory.h" +#include "pokemem.h" +#include "spectrum.h" +#include "utils.h" + +enum { + POKEFILE_NEXT_TRAINER = 'N', + POKEFILE_MORE_POKE = 'M', + POKEFILE_LAST_POKE = 'Z', + POKEFILE_EOF = 'Y' +}; + +/* Expected data while parsing a file */ +typedef enum do_t { + DO_TRAINER, + DO_POKE, + DO_EOF, +} do_t; + +char *pokfile = NULL; /* Path of a .pok file to load */ +GSList *trainer_list = NULL; /* Trainers loaded from a file */ +trainer_t *current_trainer = NULL; /* Last trainer parsed */ + +int pokemem_read_from_buffer( const libspectrum_byte *buffer, size_t length ); +int pokemem_read_poke( const libspectrum_byte **ptr, + const libspectrum_byte *end ); +int pokemem_read_trainer( const libspectrum_byte **ptr, + const libspectrum_byte *end ); +void pokemem_skip_line( const libspectrum_byte **ptr, + const libspectrum_byte *end ); +poke_t *pokemem_poke_add( trainer_t *trainer, int bank, int address, + int value, int restore ); + +static void pokemem_poke_activate( gpointer data, gpointer user_data ); +static void pokemem_poke_desactivate( gpointer data, gpointer user_data ); + +libspectrum_byte pokemem_mem_value( libspectrum_word bank, + libspectrum_word address ); + +static void +pokemem_poke_free( gpointer data, gpointer user_data GCC_UNUSED ) +{ + poke_t *poke = data; + + free( poke ); +} + +static void +pokemem_trainer_free( gpointer data, gpointer user_data GCC_UNUSED ) +{ + trainer_t *trainer = data; + + if( !trainer ) return; + + if( trainer->poke_list ) { + g_slist_foreach( trainer->poke_list, pokemem_poke_free, NULL ); + g_slist_free( trainer->poke_list ); + } + + free( trainer->name ); + free( trainer ); +} + +void +pokemem_clear( void ) +{ + if( trainer_list ) { + g_slist_foreach( trainer_list, pokemem_trainer_free, NULL ); + g_slist_free( trainer_list ); + trainer_list = NULL; + } + + free( pokfile ); + pokfile = NULL; + current_trainer = NULL; +} + +void +pokemem_end( void ) +{ + pokemem_clear(); +} + +int +pokemem_read_from_file( const char *filename ) +{ + utils_file file; + int error; + + if( !filename ) return 1; + + pokemem_clear(); + + error = utils_read_file( filename, &file ); + if( error ) return error; + + pokfile = strdup( filename ); + error = pokemem_read_from_buffer( file.buffer, file.length ); + + utils_close_file( &file ); + return error; +} + +int +pokemem_read_from_buffer( const libspectrum_byte *buffer, size_t length ) +{ + const libspectrum_byte *ptr, *end; + libspectrum_byte id; + int eop, error; + do_t do_now; + + trainer_list = NULL; + current_trainer = NULL; + ptr = buffer; + end = buffer + length; + do_now = DO_TRAINER; + eop = ( ptr >= end ); + + while( !eop ) { + + id = *ptr++; /* First char of a line */ + + switch( id ) { + + case POKEFILE_NEXT_TRAINER: + if( do_now != DO_TRAINER ) { + /* Unexpected trainer, but parse it */ + if( current_trainer ) current_trainer->disabled = 1; + } + + error = pokemem_read_trainer( &ptr, end ); + if( error ) { + if( current_trainer ) current_trainer->disabled = 1; + pokemem_skip_line( &ptr, end ); + do_now = DO_TRAINER; + } else + do_now = DO_POKE; + break; + + case POKEFILE_MORE_POKE: + if( do_now != DO_POKE ) { + /* Skip unexpected poke */ + if( current_trainer ) current_trainer->disabled = 1; + pokemem_skip_line( &ptr, end ); + do_now = DO_TRAINER; + break; + } + + pokemem_read_poke( &ptr, end ); + do_now = DO_POKE; + break; + + case POKEFILE_LAST_POKE: + /* Skip unexpected poke */ + if( do_now != DO_POKE ) { + if( current_trainer ) current_trainer->disabled = 1; + pokemem_skip_line( &ptr, end ); + do_now = DO_TRAINER; + break; + } + + pokemem_read_poke( &ptr, end ); + do_now = DO_TRAINER; + break; + + case POKEFILE_EOF: + eop = 1; + if( do_now == DO_TRAINER ) do_now = DO_EOF; + break; + + default: + /* Unknown line */ + if( do_now == DO_POKE ) { + /* Invalidate current trainer */ + if( current_trainer ) current_trainer->disabled = 1; + do_now = DO_TRAINER; + } + + pokemem_skip_line( &ptr, end ); + } + + if( ptr >= end ) eop = 1; + } + + if( do_now != DO_EOF ) { + if( current_trainer ) current_trainer->disabled = 1; + } + + return 0; +} + +void +pokemem_skip_line( const libspectrum_byte **ptr, + const libspectrum_byte *end ) +{ + const libspectrum_byte *cpos = *ptr; + + /* skip data */ + while( cpos < end && ( *cpos != '\r' && *cpos != '\n' ) ) cpos++; + + /* skip 'new line' like chars */ + while( cpos < end && ( *cpos == '\r' || *cpos == '\n' ) ) cpos++; + + *ptr = cpos; +} + +int +pokemem_read_trainer( const libspectrum_byte **ptr, + const libspectrum_byte *end ) +{ + const libspectrum_byte *cpos = *ptr; + char *title; + size_t length = 0; + + /* get trainer length */ + while( cpos < end && ( *cpos != '\0' && *cpos != '\r' && *cpos != '\n' ) ) + cpos++; + + /* store data */ + length = cpos - *ptr; + if( length > 80 ) length = 80; + title = malloc( length + 1 ); + if( !title ) return 1; + + memcpy( title, *ptr, length ); + title[ length ] = '\0'; + + current_trainer = malloc( sizeof( trainer_t ) ); + if( !current_trainer ) { + free( title ); + return 1; + } + memset( current_trainer, 0, sizeof( trainer_t ) ); + current_trainer->name = title; + trainer_list = g_slist_append( trainer_list, current_trainer ); + + /* skip 'new line' like chars */ + while( cpos < end && ( *cpos == '\r' || *cpos == '\n' ) ) cpos++; + + *ptr = cpos; + + return 0; +} + +int +pokemem_read_poke( const libspectrum_byte **ptr, const libspectrum_byte *end ) +{ + int bank, address, value, restore; + int items; + const libspectrum_byte *cpos = *ptr; + + items = sscanf( (const char *)cpos, "%1d %5d %3d %3d", + &bank, &address, &value, &restore ); + + /* skip data */ + pokemem_skip_line( ptr, end ); + + /* validate data */ + if( items < 4 ) { + current_trainer->disabled = 1; + return 1; + } + + pokemem_poke_add( current_trainer, bank, address, value, restore ); + + return 0; +} + +poke_t * +pokemem_poke_add( trainer_t *trainer, int bank, int address, int value, + int restore ) +{ + int poke_active; + poke_t *current_poke; + + if( address < 0x0000 || address > 0xffff ) { + trainer->disabled = 1; + return NULL; + } + + /* ROM on normal mode memory configuration */ + if( bank == 8 && address < 0x4000 ) { + trainer->disabled = 1; + return NULL; + } + + if( value < 0 || value > 256 ) { + trainer->disabled = 1; + return NULL; + } + + if( restore < 0 || restore > 255 ) { + trainer->disabled = 1; + return NULL; + } + + /* store data */ + current_poke = malloc( sizeof( poke_t ) ); + if( !current_poke ) { + trainer->disabled = 1; + return NULL; + } + + current_poke->bank = bank; + current_poke->address = address; + current_poke->value = value; + current_poke->restore = restore; + if( value == 256 ) trainer->ask_value = 1; + + /* Check if current poke was already applied */ + if( value <= 255 && pokemem_mem_value( bank, address ) == value ) { + poke_active = 1; + } else { + poke_active = 0; + } + + /* A trainer is active if all its pokes are applied */ + if( !trainer->poke_list ) { + trainer->active = poke_active; + } else { + trainer->active &= poke_active; + } + + trainer->poke_list = g_slist_append( trainer->poke_list, current_poke ); + + return current_poke; +} + +libspectrum_byte +pokemem_mem_value( libspectrum_word bank, libspectrum_word address ) +{ + libspectrum_byte value; + + if( bank == 8 ) { + value = readbyte_internal( address ); + } else { + value = RAM[ bank ][ address & 0x3fff ]; + } + + return value; +} + +trainer_t * +pokemem_trainer_list_add( libspectrum_byte bank, libspectrum_word address, + libspectrum_word value ) +{ + char *title; + + title = malloc( 17 ); + if( !title ) return NULL; + snprintf( title, 17, "Custom %u,%u", address, value ); + + /* Create trainer */ + current_trainer = malloc( sizeof( trainer_t ) ); + if( !current_trainer ) { + free( title ); + return NULL; + } + memset( current_trainer, 0, sizeof( trainer_t ) ); + current_trainer->name = title; + + trainer_list = g_slist_append( trainer_list, current_trainer ); + + /* Create poke */ + pokemem_poke_add( current_trainer, bank, address, value, 0 ); + + return current_trainer; +} + +int +pokemem_trainer_activate( trainer_t *trainer ) +{ + if( !trainer || trainer->disabled || !trainer->poke_list ) return 1; + + if( !trainer->active && trainer->poke_list ) { + g_slist_foreach( trainer->poke_list, pokemem_poke_activate, trainer ); + trainer->active = 1; + } + + return 0; +} + +static void +pokemem_poke_activate( gpointer data, gpointer user_data ) +{ + poke_t *poke = data; + trainer_t *trainer = user_data; + libspectrum_word bank = poke->bank; + libspectrum_word address = poke->address; + libspectrum_byte value; + + /* User custom value? */ + value = ( poke->value > 255 )? trainer->value : poke->value; + + if( bank == 8 ) { + poke->restore = readbyte_internal( address ); + writebyte_internal( address, value ); + } else { + address &= 0x3fff; + poke->restore = RAM[ bank ][ address ]; + RAM[ bank ][ address ] = value; + } +} + +int +pokemem_trainer_desactivate( trainer_t *trainer ) +{ + if( !trainer || trainer->disabled || !trainer->poke_list ) return 1; + + if( trainer->active && trainer->poke_list ) { + g_slist_foreach( trainer->poke_list, pokemem_poke_desactivate, trainer ); + trainer->active = 0; + } + + return 0; +} + +static void +pokemem_poke_desactivate( gpointer data, gpointer user_data GCC_UNUSED ) +{ + poke_t *poke = data; + libspectrum_word bank = poke->bank; + libspectrum_word address = poke->address; + libspectrum_byte value = poke->restore; + + if( bank == 8 ) { + writebyte_internal( address, value ); + } else { + RAM[ bank ][ address & 0x3fff ] = value; + } + +} + +/* Open or Drag'n'Drop a .pok file */ +int +pokemem_set_pokfile( const char *filename ) +{ + pokemem_clear(); + + if( !compat_file_exists( filename ) ) + return 1; + + pokfile = strdup( filename ); + + return 0; +} + +/* Automatic search after the load of snapshots or tapes */ +int +pokemem_find_pokfile( const char *path ) +{ + int n, has_extension; + size_t length, filename_size, last_dot, last_slash; + char *test_file, *c; + + if( pokfile ) return 1; /* Previous .pok file already found */ + + length = strlen( path ); + if( !length ) return 1; /* Nothing to search */ + + test_file = malloc( length + 11 ); + if( !test_file ) return 1; + + memcpy( test_file, path, length + 1 ); + + c = strrchr( test_file, FUSE_DIR_SEP_CHR ); + last_slash = ( c )? c - test_file : -1; + + c = strrchr( test_file, '.' ); + last_dot = ( c )? c - test_file : -1; + + has_extension = ( last_dot > last_slash ); + + /* Try .pok extension */ + if( has_extension ) { + n = last_dot; /* Replace file extension */ + test_file[n] = '\0'; + } else { + n = length; /* Append file extension */ + } + + strncat( test_file, ".pok", 4 ); + if( compat_file_exists( test_file ) ) { + pokfile = test_file; + return 0; + } + + /* Try .POK extension */ + /* FIXME: Is filesystem case sensitive? */ + memcpy( &(test_file[n]), ".POK", 4 ); + if( compat_file_exists( test_file ) ) { + pokfile = test_file; + return 0; + } + + /* Browse POKES/ directory */ + if( last_slash ) { + n = last_slash + 1; /* insert directory */ + filename_size = ( has_extension )? last_dot - last_slash - 1 : + strlen( &path[n] ); + test_file[ n ] = '\0'; + strncat( test_file, "POKES", 5 ); + } else { + n = 0; /* prepend directory */ + filename_size = ( has_extension )? last_dot : length; + strncpy( test_file, "POKES", 5 ); + test_file[ 5 ] = '\0'; + } + + /* Try .pok extension */ + strncat( test_file, FUSE_DIR_SEP_STR, 1 ); + strncat( test_file, &path[ n ], filename_size ); + strncat( test_file, ".pok", 4 ); + + if( compat_file_exists( test_file ) ) { + pokfile = test_file; + return 0; + } + + /* Try .POK extension */ + /* FIXME: Is filesystem case sensitive? */ + n = n + 6 + filename_size; + memcpy( &test_file[ n ], ".POK", 4 ); + + if( compat_file_exists( test_file ) ) { + pokfile = test_file; + return 0; + } + + free( test_file ); + + return 1; +} + +/* Finally load requested from UI */ +int +pokemem_autoload_pokfile( void ) +{ + utils_file file; + int error; + + if( !pokfile || trainer_list ) return 1; + + error = utils_read_file( pokfile, &file ); + if( error ) return error; + + error = pokemem_read_from_buffer( file.buffer, file.length ); + utils_close_file( &file ); + + return error; +} Property changes on: trunk/fuse/pokefinder/pokemem.c ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native Added: trunk/fuse/pokefinder/pokemem.h =================================================================== --- trunk/fuse/pokefinder/pokemem.h (rev 0) +++ trunk/fuse/pokefinder/pokemem.h 2011-08-11 12:59:47 UTC (rev 4534) @@ -0,0 +1,69 @@ +/* pokemem.h: help with handling pokes + Copyright (c) 2011 Philip Kendall, Sergio Baldoví + + $Id$ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + Author contact information: + + E-mail: phi...@sh... + +*/ + +#ifndef POKEMEM_H +#define POKEMEM_H + +#include <config.h> + +#ifdef HAVE_LIB_GLIB +#include <glib.h> +#endif /* #ifdef HAVE_LIB_GLIB */ + +#include <libspectrum.h> + +extern GSList *trainer_list; + +typedef struct trainer_t { + char *name; + int disabled; /* malformed trainer or pokes? */ + int ask_value; /* request user for a value */ + libspectrum_byte value; /* user's custom value */ + int active; /* pokes applied? */ + GSList *poke_list; +} trainer_t; + +typedef struct poke_t { + libspectrum_byte bank; /* 8 means ignore bank */ + libspectrum_word address; /* address to poke */ + libspectrum_word value; /* 256 means request to user */ + libspectrum_byte restore; /* original value before poke */ +} poke_t; + +void pokemem_clear( void ); +void pokemem_end( void ); +int pokemem_set_pokfile( const char *filename ); +int pokemem_find_pokfile( const char *filename ); +int pokemem_autoload_pokfile( void ); +int pokemem_read_from_file( const char *filename ); + +trainer_t *pokemem_trainer_list_add( libspectrum_byte bank, + libspectrum_word address, + libspectrum_word value ); + +int pokemem_trainer_activate( trainer_t *trainer ); +int pokemem_trainer_desactivate( trainer_t *trainer ); + +#endif Property changes on: trunk/fuse/pokefinder/pokemem.h ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native Modified: trunk/fuse/ui/fb/fbui.c =================================================================== --- trunk/fuse/ui/fb/fbui.c 2011-08-08 12:44:34 UTC (rev 4533) +++ trunk/fuse/ui/fb/fbui.c 2011-08-11 12:59:47 UTC (rev 4534) @@ -113,3 +113,9 @@ fbkeyboard_end(); uidisplay_end(); } + +void +ui_pokemem_selector( const char *filename ) +{ + /* TODO: implement this */ +} Modified: trunk/fuse/ui/gtk/Makefile.am =================================================================== --- trunk/fuse/ui/gtk/Makefile.am 2011-08-08 12:44:34 UTC (rev 4533) +++ trunk/fuse/ui/gtk/Makefile.am 2011-08-11 12:59:47 UTC (rev 4534) @@ -46,6 +46,7 @@ picture.c \ pixmaps.c \ pokefinder.c \ + pokemem.c \ rollback.c \ roms.c \ statusbar.c \ Added: trunk/fuse/ui/gtk/pokemem.c =================================================================== --- trunk/fuse/ui/gtk/pokemem.c (rev 0) +++ trunk/fuse/ui/gtk/pokemem.c 2011-08-11 12:59:47 UTC (rev 4534) @@ -0,0 +1,591 @@ +/* pokemem.c: GTK+ interface that handles pok files + Copyright (c) 2011 Philip Kendall, Sergio Baldoví + + $Id$ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + Author contact information: + + E-mail: phi...@sh... + +*/ + +#include <config.h> +#include <ctype.h> +#include <errno.h> + +#include <gdk/gdkkeysyms.h> +#include <gtk/gtk.h> + +#include "fuse.h" +#include "gtkinternals.h" +#include "menu.h" +#include "pokefinder/pokemem.h" +#include "ui/ui.h" + +enum +{ + COL_CHECK = 0, + COL_NAME, + COL_VALUE, + COL_TRAINER, + COL_ENABLED, + COL_EDITABLE, + COL_INCONSISTENT, + NUM_COLS +}; + +static GtkWidget + *dialog, /* The dialog box itself */ + *poke_list, /* The list of possible pokes */ + *bank, /* Entries for custom poke */ + *address, + *value; + +void create_dialog( void ); +void create_and_fill_treeview( void ); +static void pokemem_close( GtkWidget *widget, gpointer user_data ); +static void pokemem_update_list( GtkWidget *widget, gpointer user_data ); +gboolean pokemem_update_trainer( GtkTreeModel *model, GtkTreePath *path, + GtkTreeIter *iter, gpointer data ); +static void pokemem_add_custom_poke( GtkWidget *widget, gpointer user_data ); +static void trainer_add( gpointer data, gpointer user_data ); + +void entry_validate_digit( GtkEntry *entry, const gchar *text, gint length, + gint *position, gpointer data ); +void entry_validate_address( GtkEntry *entry, const gchar *text, gint length, + gint *position, gpointer data ); + +void row_toggled_callback( GtkCellRendererToggle *cell, gchar *path_string, + gpointer user_data ); + +static gboolean custom_value_edit( GtkTreeView *tree ); +void custom_value_changed( GtkCellRendererText *cell, gchar *path_string, + gchar *new_text, gpointer user_data ); + +void +menu_machine_pokememory( GtkWidget *widget GCC_UNUSED, + gpointer data GCC_UNUSED ) +{ + pokemem_autoload_pokfile(); + create_dialog(); +} + +void +ui_pokemem_selector( const char *filename ) +{ + pokemem_read_from_file( filename ); + create_dialog(); +} + +void +create_dialog( void ) +{ + GtkWidget *hbox, *vbox, *label, *scroll; + GtkAccelGroup *accel_group; + + fuse_emulation_pause(); + + dialog = gtkstock_dialog_new( "Fuse - Poke Memory", + GTK_SIGNAL_FUNC( pokemem_close ) ); + + vbox = GTK_DIALOG( dialog )->vbox; + + /* Keyboard shortcuts */ + accel_group = gtk_accel_group_new(); + gtk_window_add_accel_group( GTK_WINDOW( dialog ), accel_group ); + + hbox = gtk_hbox_new( FALSE, 0 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, TRUE, TRUE, 5 ); + + /* Bank */ + label = gtk_label_new( "Bank:" ); + bank = gtk_entry_new(); + gtk_entry_set_width_chars( GTK_ENTRY( bank ), 7 ); + gtk_entry_set_max_length( GTK_ENTRY( bank ), 1 ); + gtk_signal_connect( GTK_OBJECT( bank ), "activate", + GTK_SIGNAL_FUNC( pokemem_add_custom_poke ), NULL ); + gtk_signal_connect( GTK_OBJECT( bank ), "insert_text", + GTK_SIGNAL_FUNC( entry_validate_digit ), NULL ); + gtk_box_pack_start( GTK_BOX( hbox ), label, TRUE, TRUE, 5 ); + gtk_box_pack_start( GTK_BOX( hbox ), bank, TRUE, TRUE, 5 ); + + /* Address */ + label = gtk_label_new( "Address:" ); + address = gtk_entry_new(); + gtk_entry_set_width_chars( GTK_ENTRY( address ), 7 ); + gtk_entry_set_max_length( GTK_ENTRY( address ), 6 ); + gtk_signal_connect( GTK_OBJECT( address ), "activate", + GTK_SIGNAL_FUNC( pokemem_add_custom_poke ), NULL ); + gtk_signal_connect( GTK_OBJECT( address ), "insert_text", + GTK_SIGNAL_FUNC( entry_validate_address ), NULL ); + gtk_box_pack_start( GTK_BOX( hbox ), label, TRUE, TRUE, 5 ); + gtk_box_pack_start( GTK_BOX( hbox ), address, TRUE, TRUE, 5 ); + + /* Value */ + label = gtk_label_new( "Value:" ); + value = gtk_entry_new(); + gtk_entry_set_width_chars( GTK_ENTRY( value ), 7 ); + gtk_entry_set_max_length( GTK_ENTRY( value ), 3 ); + gtk_signal_connect( GTK_OBJECT( value ), "activate", + GTK_SIGNAL_FUNC( pokemem_add_custom_poke ), NULL ); + gtk_signal_connect( GTK_OBJECT( value ), "insert_text", + GTK_SIGNAL_FUNC( entry_validate_digit ), NULL ); + gtk_box_pack_start( GTK_BOX( hbox ), label, TRUE, TRUE, 5 ); + gtk_box_pack_start( GTK_BOX( hbox ), value, TRUE, TRUE, 5 ); + + /* Create Add button for custom pokes */ + static const gtkstock_button + add = { "Add", GTK_SIGNAL_FUNC( pokemem_add_custom_poke ), NULL, NULL, + 0, 0, 0, 0 }; + gtkstock_create_button( GTK_WIDGET( hbox ), accel_group, &add ); + + label = gtk_label_new( "Choose active POKES:" ); + gtk_box_pack_start( GTK_BOX( vbox ), label, TRUE, TRUE, 5 ); + + /* Create list widget */ + create_and_fill_treeview(); + scroll = gtk_scrolled_window_new( NULL, NULL ); + gtk_container_add( GTK_CONTAINER( scroll ), GTK_WIDGET( poke_list ) ); + gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( scroll ), TRUE, TRUE, 5 ); + + /* Create and add the actions buttons to the dialog box */ + gtkstock_create_ok_cancel( dialog, accel_group, + GTK_SIGNAL_FUNC( pokemem_update_list ), + (gpointer) &dialog, + GTK_SIGNAL_FUNC( pokemem_close ) ); + gtk_accel_group_disconnect_key( accel_group, GDK_Return, 0 ); + + /* Users shouldn't be able to resize this window */ + gtk_window_set_policy( GTK_WINDOW( dialog ), FALSE, FALSE, TRUE ); + + /* Process the dialog */ + gtk_widget_show_all( dialog ); + gtk_main(); + + fuse_emulation_unpause(); +} + +void +create_and_fill_treeview( void ) +{ + GtkListStore *store; + GtkCellRenderer *renderer; + GtkTreeModel *model; + + poke_list = gtk_tree_view_new(); + gtk_tree_view_set_rules_hint( GTK_TREE_VIEW( poke_list ), TRUE ); + + store = gtk_list_store_new( NUM_COLS, G_TYPE_BOOLEAN, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN, + G_TYPE_BOOLEAN, G_TYPE_BOOLEAN ); + + renderer = gtk_cell_renderer_toggle_new(); + + /* First column, checkbox */ + g_signal_connect( renderer, "toggled", + (GCallback) row_toggled_callback, + (gpointer) GTK_TREE_MODEL( store ) ); + + gtk_tree_view_insert_column_with_attributes( GTK_TREE_VIEW( poke_list ), + -1, + "Active", + renderer, + "active", COL_CHECK, + "activatable", COL_ENABLED, + "inconsistent", COL_INCONSISTENT, + NULL ); + + /* Second column, name */ + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes( GTK_TREE_VIEW( poke_list ), + -1, + "Trainer", + renderer, + "text", COL_NAME, + NULL ); + + /* Third column, optional value */ + renderer = gtk_cell_renderer_text_new(); + g_signal_connect( renderer, "edited", (GCallback)custom_value_changed, + (gpointer) GTK_TREE_MODEL( store ) ); + + gtk_tree_view_insert_column_with_attributes( GTK_TREE_VIEW( poke_list ), + -1, + "Value", + renderer, + "text", COL_VALUE, + "editable", COL_EDITABLE, + NULL); + + /* Create and fill model */ + if( trainer_list ) { + g_slist_foreach( trainer_list, trainer_add, store ); + } + model = GTK_TREE_MODEL( store ); + + gtk_tree_view_set_model( GTK_TREE_VIEW( poke_list ), model ); + + g_object_unref( model ); + + /* Adjust size for list */ + GtkRequisition size; + gtk_widget_size_request( GTK_WIDGET( poke_list ), &size ); + size.height = 200; + gtk_widget_set_size_request( GTK_WIDGET( poke_list ), -1, size.height ); +} + +static void +trainer_add( gpointer data, gpointer user_data ) +{ + gchar *val = NULL; + GtkListStore *store = user_data; + GtkTreeIter iter; + trainer_t *trainer = data; + + if( !trainer ) return; + + if( trainer->ask_value ) + val = g_strdup_printf( "%d", trainer->value ); + + /* Append a new row and fill data */ + gtk_list_store_append( store, &iter ); + gtk_list_store_set( store, &iter, + COL_CHECK, trainer->active, + COL_NAME, trainer->name, + COL_VALUE, ( trainer->ask_value )? val : NULL, + COL_TRAINER, trainer, + COL_ENABLED, !trainer->disabled, + COL_EDITABLE, ( !trainer->disabled && !trainer->active + && trainer->ask_value ), + COL_INCONSISTENT, ( trainer->disabled && !trainer->active ), + -1); + + g_free( val ); +} + +static void +pokemem_close( GtkWidget *widget, gpointer user_data GCC_UNUSED ) +{ + gtkui_destroy_widget_and_quit( widget, NULL ); +} + +static void +pokemem_update_list( GtkWidget *widget GCC_UNUSED, + gpointer user_data GCC_UNUSED ) +{ + GtkTreeModel *model; + + model = gtk_tree_view_get_model( GTK_TREE_VIEW( poke_list ) ); + if( model ) { + gtk_tree_model_foreach( model, pokemem_update_trainer, NULL ); + } + + gtkui_destroy_widget_and_quit( dialog, NULL ); +} + +gboolean +pokemem_update_trainer( GtkTreeModel *model, GtkTreePath *path GCC_UNUSED, + GtkTreeIter *iter, gpointer data GCC_UNUSED ) +{ + gboolean selected; + gchar *name; + trainer_t *trainer; + + gtk_tree_model_get( model, iter, + COL_CHECK, &selected, + COL_NAME, &name, + COL_TRAINER, &trainer, + -1); + + if( selected ) { + pokemem_trainer_activate( trainer ); + } else { + pokemem_trainer_desactivate( trainer ); + } + + g_free( name ); + + return FALSE; +} + +static void +pokemem_add_custom_poke( GtkWidget *widget GCC_UNUSED, + gpointer user_data GCC_UNUSED ) +{ + long b, a, v; + const gchar *entry; + char *endptr; + int base; + trainer_t *trainer; + GtkListStore *store; + + if( gtk_entry_get_text_length( GTK_ENTRY( address ) ) == 0 && + gtk_entry_get_text_length( GTK_ENTRY( value ) ) == 0 ) { + return; + } + + /* Parse bank */ + entry = gtk_entry_get_text( GTK_ENTRY( bank ) ); + errno = 0; + b = strtol( entry, &endptr, 10 ); + if( errno || b < 0 || b > 8 ) { + ui_error( UI_ERROR_ERROR, "Invalid bank: use an integer from 0 to 8" ); + gtk_widget_grab_focus( bank ); + return; + } + + if( endptr == entry ) b = 8; /* ignore bank by default */ + + /* Parse address */ + entry = gtk_entry_get_text( GTK_ENTRY( address ) ); + errno = 0; + base = ( g_str_has_prefix( entry, "0x" ) )? 16 : 10; + a = strtol( entry, &endptr, base ); + + if( errno || a < 0 || a > 65535 || endptr == entry ) { + ui_error( UI_ERROR_ERROR, + "Invalid address: use an integer from 0 to 65535" ); + gtk_widget_grab_focus( address ); + return; + } + + if( b == 8 && a < 16384 ) { + ui_error( UI_ERROR_ERROR, + "Invalid address: use an integer from 16384 to 65535" ); + gtk_widget_grab_focus( address ); + return; + } + + /* Parse value */ + entry = gtk_entry_get_text( GTK_ENTRY( value ) ); + errno = 0; + v = strtol( entry, &endptr, 10 ); + + if( errno || v < 0 || v > 256 || endptr == entry ) { + ui_error( UI_ERROR_ERROR, "Invalid value: use an integer from 0 to 256" ); + gtk_widget_grab_focus( value ); + return; + } + + /* Updadate store and view */ + trainer = pokemem_trainer_list_add( b, a, v ); + if( trainer ) { + store = GTK_LIST_STORE( gtk_tree_view_get_model( + GTK_TREE_VIEW( poke_list ) ) ); + trainer_add( trainer, store ); + } + + /* Mark custom trainer for activate */ + GtkTreeModel *model; + GtkTreePath *path; + GtkTreeIter iter; + int rows; + + if( !trainer->active && !trainer->disabled ) { + model = gtk_tree_view_get_model( GTK_TREE_VIEW( poke_list ) ); + rows = gtk_tree_model_iter_n_children( model, NULL ); + path = gtk_tree_path_new_from_indices( rows - 1, -1 ); + gtk_tree_model_get_iter( model, &iter, path ); + gtk_list_store_set( GTK_LIST_STORE( model ), &iter, COL_CHECK, TRUE, -1 ); + gtk_tree_path_free( path ); + } + + /* Clear custom fields */ + gtk_editable_delete_text( GTK_EDITABLE( bank ), 0, -1 ); + gtk_editable_delete_text( GTK_EDITABLE( address ), 0, -1 ); + gtk_editable_delete_text( GTK_EDITABLE( value ), 0, -1 ); + gtk_widget_grab_focus( address ); +} + +void +entry_validate_digit( GtkEntry *entry, const gchar *text, gint length, + gint *position, gpointer data ) +{ + int i, count = 0; + GtkEditable *editable = GTK_EDITABLE( entry ); + gchar *result = g_new( gchar, length ); + + /* Validate decimal and fill buffer to insert */ + for( i = 0; i < length; i++ ) { + if( !isdigit( text[i] ) ) continue; + + result[ count++ ] = text[i]; + } + + /* Insert only validated text */ + if( count > 0 ) { + g_signal_handlers_block_by_func( G_OBJECT( editable ), + G_CALLBACK( entry_validate_digit ), + data ); + gtk_editable_insert_text( editable, result, count, position ); + g_signal_handlers_unblock_by_func( G_OBJECT( editable ), + G_CALLBACK( entry_validate_digit ), + data ); + } + g_signal_stop_emission_by_name( G_OBJECT( editable ), "insert_text" ); + + g_free( result ); +} + +void +entry_validate_address( GtkEntry *entry, const gchar *text, gint length, + gint *position, gpointer data ) +{ + int i, is_valid, is_hex; + size_t n, prev_length, max_length, count = 0; + GtkEditable *editable = GTK_EDITABLE( entry ); + GString *full_text; + gchar *result = NULL; + + /* Validate hex or decimal number */ + full_text = g_string_new( gtk_entry_get_text( entry ) ); + prev_length = full_text->len; + full_text = g_string_insert_len( full_text, *position, text, length ); + is_valid = 1; + is_hex = 0; + + for( n = 0; n < full_text->len && is_valid; n++ ) { + + switch( n ) { + case 0: + is_valid = isdigit( full_text->str[n] ); + break; + + case 1: + if( full_text->str[n] == 'x' ) { + if( full_text->str[0] == '0' ) is_hex = 1; + is_valid = is_hex; + } else { + is_valid = isdigit( full_text->str[n] ); + } + break; + + default: + is_valid = ( is_hex )? isxdigit( full_text->str[n] ) : + isdigit( full_text->str[n] ); + } + + } + g_string_free( full_text, TRUE ); + + /* Fill buffer to insert */ + if( is_valid ) { + max_length = ( is_hex )? 6 : 5; + result = g_new( gchar, length ); + + for( i = 0; i < length && i + prev_length < max_length; i++ ) { + result[ count++ ] = text[i]; + } + } + + /* Insert only validated text */ + if( count > 0 ) { + g_signal_handlers_block_by_func( G_OBJECT( editable ), + G_CALLBACK( entry_validate_address ), + data ); + gtk_editable_insert_text( editable, result, count, position ); + g_signal_handlers_unblock_by_func( G_OBJECT( editable ), + G_CALLBACK( entry_validate_address ), + data ); + } + + g_signal_stop_emission_by_name( G_OBJECT( editable ), "insert_text" ); + g_free( result ); +} + +void +row_toggled_callback( GtkCellRendererToggle *cell GCC_UNUSED, + gchar *path_string, gpointer user_data ) +{ + GtkTreeIter iter; + GtkTreeModel *model = user_data; + GValue val, gtrainer; + trainer_t *trainer; + gboolean flag; + + /* Toggle current selection */ + gtk_tree_model_get_iter_from_string( model, &iter, path_string ); + memset( &val, 0, sizeof( val ) ); + gtk_tree_model_get_value( model, &iter, COL_CHECK, &val ); + flag = !g_value_get_boolean( &val ); + g_value_unset( &val ); + gtk_list_store_set( GTK_LIST_STORE( model ), &iter, COL_CHECK, flag, -1 ); + + /* Request user for custom value */ + if( flag ) { + memset( >rainer, 0, sizeof( gtrainer ) ); + gtk_tree_model_get_value( model, &iter, COL_TRAINER, >rainer ); + trainer = (trainer_t *)g_value_get_pointer( >rainer ); + g_value_unset( >rainer ); + + if( trainer->ask_value ) { + g_idle_add( (GSourceFunc)custom_value_edit, GTK_TREE_VIEW( poke_list ) ); + } + } +} + +static gboolean +custom_value_edit( GtkTreeView *tree ) +{ + GtkTreePath *path; + GtkTreeViewColumn *col, *col_current; + + gtk_tree_view_get_cursor( tree, &path, &col_current ); + if( !path || !col_current ) return FALSE; + + col = gtk_tree_view_get_column( tree, COL_VALUE ); + gtk_tree_view_set_cursor( tree, path, col, TRUE ); + gtk_tree_path_free( path ); + + return FALSE; +} + +void +custom_value_changed( GtkCellRendererText *cell GCC_UNUSED, gchar *path_string, + gchar *new_text, gpointer user_data ) +{ + GtkTreeModel *model = (GtkTreeModel *)user_data; + GtkTreeIter iter; + GValue val; + gchar *str_value; + trainer_t *trainer; + long v; + char *endptr; + + if( gtk_tree_model_get_iter_from_string( model, &iter, path_string ) ) { + memset( &val, 0, sizeof( val ) ); + + gtk_tree_model_get_value( model, &iter, COL_TRAINER, &val ); + trainer = (trainer_t *)g_value_get_pointer( &val ); + g_value_unset( &val ); + + errno = 0; + v = strtol( new_text, &endptr, 10 ); + + if( errno || v < 0 || v > 255 || endptr == new_text ) { + ui_error( UI_ERROR_ERROR, "Invalid value: use an integer from 0 to 255" ); + return; + } + + trainer->value = v; + str_value = g_strdup_printf( "%d", trainer->value ); + + gtk_list_store_set( GTK_LIST_STORE( model ), &iter, + COL_VALUE, str_value, -1); + g_free( str_value ); + } +} Property changes on: trunk/fuse/ui/gtk/pokemem.c ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native Modified: trunk/fuse/ui/sdl/sdlui.c =================================================================== --- trunk/fuse/ui/sdl/sdlui.c 2011-08-08 12:44:34 UTC (rev 4533) +++ trunk/fuse/ui/sdl/sdlui.c 2011-08-11 12:59:47 UTC (rev 4534) @@ -197,3 +197,9 @@ SDL_ShowCursor( SDL_ENABLE ); return 0; } + +void +ui_pokemem_selector( const char *filename ) +{ + /* TODO: implement this */ +} Modified: trunk/fuse/ui/svga/svgaui.c =================================================================== --- trunk/fuse/ui/svga/svgaui.c 2011-08-08 12:44:34 UTC (rev 4533) +++ trunk/fuse/ui/svga/svgaui.c 2011-08-11 12:59:47 UTC (rev 4534) @@ -124,3 +124,9 @@ { return !suspend; } + +void +ui_pokemem_selector( const char *filename ) +{ + /* TODO: implement this */ +} Modified: trunk/fuse/ui/ui.h =================================================================== --- trunk/fuse/ui/ui.h 2011-08-08 12:44:34 UTC (rev 4533) +++ trunk/fuse/ui/ui.h 2011-08-11 12:59:47 UTC (rev 4534) @@ -295,4 +295,6 @@ void ui_widget_keyhandler( int native_key ); +void ui_pokemem_selector( const char *filename ); + #endif /* #ifndef FUSE_UI_H */ Modified: trunk/fuse/ui/win32/win32ui.c =================================================================== --- trunk/fuse/ui/win32/win32ui.c 2011-08-08 12:44:34 UTC (rev 4533) +++ trunk/fuse/ui/win32/win32ui.c 2011-08-11 12:59:47 UTC (rev 4534) @@ -1170,3 +1170,9 @@ } /* FIXME: somewhere there should be return msg.wParam */ } + +void +ui_pokemem_selector( const char *filename ) +{ + /* TODO: implement this */ +} Modified: trunk/fuse/utils.c =================================================================== --- trunk/fuse/utils.c 2011-08-08 12:44:34 UTC (rev 4533) +++ trunk/fuse/utils.c 2011-08-11 12:59:47 UTC (rev 4534) @@ -46,6 +46,7 @@ #include "peripherals/ide/zxcf.h" #include "peripherals/if1.h" #include "peripherals/if2.h" +#include "pokefinder/pokemem.h" #include "rzx.h" #include "screenshot.h" #include "settings.h" @@ -105,11 +106,13 @@ case LIBSPECTRUM_CLASS_SNAPSHOT: error = snapshot_read_buffer( file.buffer, file.length, type ); + pokemem_find_pokfile( filename ); break; case LIBSPECTRUM_CLASS_TAPE: error = tape_read_buffer( file.buffer, file.length, type, filename, autoload ); + pokemem_find_pokfile( filename ); break; case LIBSPECTRUM_CLASS_DISK_PLUS3: @@ -196,6 +199,12 @@ break; + case LIBSPECTRUM_CLASS_AUXILIARY: + if( type == LIBSPECTRUM_ID_AUX_POK ) { + ui_pokemem_selector( filename ); + } + break; + default: ui_error( UI_ERROR_ERROR, "utils_open_file: unknown class %d", type ); error = 1; Modified: trunk/libspectrum/hacking/ChangeLog =================================================================== --- trunk/libspectrum/hacking/ChangeLog 2011-08-08 12:44:34 UTC (rev 4533) +++ trunk/libspectrum/hacking/ChangeLog 2011-08-11 12:59:47 UTC (rev 4534) @@ -850,3 +850,5 @@ 20100515 tap.c: add support for the TZX set signal level block (Fred). 20100515 tzx_write.c: factor out common code for writing signal level and pure tone blocks (Fred). +20100811 libspectrum.h.in,libspectrum.c: add support for detecting POK files + (patch #3382538) (Sergio Baldoví). Modified: trunk/libspectrum/libspectrum.c =================================================================== --- trunk/libspectrum/libspectrum.c 2011-08-08 12:44:34 UTC (rev 4533) +++ trunk/libspectrum/libspectrum.c 2011-08-11 12:59:47 UTC (rev 4534) @@ -553,6 +553,8 @@ { LIBSPECTRUM_ID_DISK_OPD, "opd", 3, NULL, 0, 0, 0 }, { LIBSPECTRUM_ID_DISK_OPD, "opu", 3, NULL, 0, 0, 0 }, + { LIBSPECTRUM_ID_AUX_POK, "pok", 3, NULL, 0, 0, 0 }, + { -1, NULL, 0, NULL, 0, 0, 0 }, /* End marker */ }; @@ -721,6 +723,8 @@ case LIBSPECTRUM_ID_DISK_TD0: *libspectrum_class = LIBSPECTRUM_CLASS_DISK_GENERIC; return 0; + case LIBSPECTRUM_ID_AUX_POK: + *libspectrum_class = LIBSPECTRUM_CLASS_AUXILIARY; return 0; } libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN, Modified: trunk/libspectrum/libspectrum.h.in =================================================================== --- trunk/libspectrum/libspectrum.h.in 2011-08-08 12:44:34 UTC (rev 4533) +++ trunk/libspectrum/libspectrum.h.in 2011-08-11 12:59:47 UTC (rev 4534) @@ -212,6 +212,8 @@ LIBSPECTRUM_ID_TAPE_PZX, /* PZX tape image */ + LIBSPECTRUM_ID_AUX_POK, /* POKE file */ + } libspectrum_id_t; /* And 'classes' of file */ @@ -248,6 +250,8 @@ LIBSPECTRUM_CLASS_DISK_GENERIC, /* generic disk image */ + LIBSPECTRUM_CLASS_AUXILIARY, /* auxiliary supported file */ + } libspectrum_class_t; WIN32_DLL libspectrum_error This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |