forked from Miroirs/x49gp
use getopt_long to parse options, change semantic of -d and -F slightly
This commit is contained in:
parent
a22ae17352
commit
6fe6c501b0
2 changed files with 115 additions and 260 deletions
1
Makefile
1
Makefile
|
@ -102,6 +102,7 @@ X49GP_CFLAGS = -O2 \
|
||||||
$(DEBUG) \
|
$(DEBUG) \
|
||||||
$(INCLUDES) \
|
$(INCLUDES) \
|
||||||
$(DEFINES) \
|
$(DEFINES) \
|
||||||
|
-D_GNU_SOURCE=1 \
|
||||||
-DVERSION_MAJOR=$(VERSION_MAJOR) \
|
-DVERSION_MAJOR=$(VERSION_MAJOR) \
|
||||||
-DVERSION_MINOR=$(VERSION_MINOR) \
|
-DVERSION_MINOR=$(VERSION_MINOR) \
|
||||||
-DPATCHLEVEL=$(PATCHLEVEL) \
|
-DPATCHLEVEL=$(PATCHLEVEL) \
|
||||||
|
|
374
src/main.c
374
src/main.c
|
@ -13,6 +13,8 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <getopt.h>
|
||||||
|
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
|
@ -21,8 +23,6 @@
|
||||||
#include "x49gp.h"
|
#include "x49gp.h"
|
||||||
#include "x49gp_ui.h"
|
#include "x49gp_ui.h"
|
||||||
#include "s3c2410.h"
|
#include "s3c2410.h"
|
||||||
#include "s3c2410_power.h"
|
|
||||||
#include "s3c2410_timer.h"
|
|
||||||
#include "x49gp_timer.h"
|
#include "x49gp_timer.h"
|
||||||
|
|
||||||
#include "gdbstub.h"
|
#include "gdbstub.h"
|
||||||
|
@ -54,9 +54,9 @@ int singlestep;
|
||||||
#if !( defined( __APPLE__ ) || defined( _POSIX_C_SOURCE ) && !defined( __sun__ ) )
|
#if !( defined( __APPLE__ ) || defined( _POSIX_C_SOURCE ) && !defined( __sun__ ) )
|
||||||
static void* oom_check( void* ptr )
|
static void* oom_check( void* ptr )
|
||||||
{
|
{
|
||||||
if ( ptr == NULL ) {
|
if ( ptr == NULL )
|
||||||
abort();
|
abort();
|
||||||
}
|
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -228,6 +228,10 @@ void x49gp_lcd_timer( void* data )
|
||||||
x49gp_mod_timer( x49gp->lcd_timer, expires );
|
x49gp_mod_timer( x49gp->lcd_timer, expires );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********/
|
||||||
|
/* OPTIONS */
|
||||||
|
/***********/
|
||||||
|
|
||||||
struct options {
|
struct options {
|
||||||
char* config;
|
char* config;
|
||||||
int debug_port;
|
int debug_port;
|
||||||
|
@ -238,272 +242,128 @@ struct options {
|
||||||
int more_options;
|
int more_options;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct option_def;
|
struct options opt;
|
||||||
|
|
||||||
typedef int ( *option_action )( struct options* opt, struct option_def* match, char* this_opt, char* param, char* progname );
|
static void config_init( char* progname, int argc, char* argv[] )
|
||||||
|
|
||||||
struct option_def {
|
|
||||||
option_action action;
|
|
||||||
char* longname;
|
|
||||||
char shortname;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int action_help( struct options* opt, struct option_def* match, char* this_opt, char* param, char* progname );
|
|
||||||
static int action_debuglater( struct options* opt, struct option_def* match, char* this_opt, char* param, char* progname );
|
|
||||||
static int action_debug( struct options* opt, struct option_def* match, char* this_opt, char* param, char* progname );
|
|
||||||
static int action_reinit_flash( struct options* opt, struct option_def* match, char* this_opt, char* param, char* progname );
|
|
||||||
static int action_reinit_flash_full( struct options* opt, struct option_def* match, char* this_opt, char* param, char* progname );
|
|
||||||
static int action_reboot( struct options* opt, struct option_def* match, char* this_opt, char* param, char* progname );
|
|
||||||
|
|
||||||
static int action_unknown_with_param( struct options* opt, struct option_def* match, char* this_opt, char* param, char* progname );
|
|
||||||
static int action_longopt( struct options* opt, struct option_def* match, char* this_opt, char* param, char* progname );
|
|
||||||
static int action_endopt( struct options* opt, struct option_def* match, char* this_opt, char* param, char* progname );
|
|
||||||
|
|
||||||
struct option_def option_defs[] = {
|
|
||||||
{action_help, "help", 'h' },
|
|
||||||
{action_debuglater, "enable-debug", 'D' },
|
|
||||||
{action_debug, "debug", 'd' },
|
|
||||||
{action_reinit_flash, "reflash", 'f' },
|
|
||||||
{action_reinit_flash_full, "reflash-full", 'F' },
|
|
||||||
{action_reboot, "reboot", 'r' },
|
|
||||||
|
|
||||||
{action_longopt, NULL, '-' },
|
|
||||||
{action_unknown_with_param, NULL, '=' },
|
|
||||||
{action_endopt, "", '\0'}
|
|
||||||
};
|
|
||||||
|
|
||||||
static void warn_unneeded_param( struct option_def* match, char* this_opt )
|
|
||||||
{
|
{
|
||||||
if ( this_opt[ 1 ] == '-' ) {
|
int option_index;
|
||||||
fprintf( stderr,
|
int c = '?';
|
||||||
"The option \"--%s\" does not support"
|
|
||||||
" parameters\n",
|
|
||||||
match->longname );
|
|
||||||
} else
|
|
||||||
fprintf( stderr, "The option '-%c' does not support parameters\n", match->shortname );
|
|
||||||
}
|
|
||||||
|
|
||||||
static int action_help( struct options* opt, struct option_def* match, char* this_opt, char* param, char* progname )
|
opt.config = NULL;
|
||||||
{
|
opt.debug_port = 0;
|
||||||
if ( param != NULL )
|
opt.start_debugger = false;
|
||||||
warn_unneeded_param( match, this_opt );
|
opt.reinit = X49GP_REINIT_NONE;
|
||||||
|
opt.firmware = NULL;
|
||||||
|
|
||||||
fprintf( stderr,
|
const char* optstring = "hrc:D:df:F";
|
||||||
"%s %i.%i.%i Emulator for HP 49G+ / 50G calculators\n"
|
struct option long_options[] = {
|
||||||
"Usage: %s [<options>] [<config-file>]\n"
|
{"help", no_argument, NULL, 'h'},
|
||||||
"Valid options:\n"
|
|
||||||
" -D, --enable-debug[=<port] enable the debugger interface\n"
|
|
||||||
" (default port: %u)\n"
|
|
||||||
" -d, --debug[=<port>] like -D, but also start the"
|
|
||||||
" debugger immediately\n"
|
|
||||||
" -f, --reflash[=firmware] rebuild the flash using the"
|
|
||||||
" supplied firmware\n"
|
|
||||||
" (default: select one"
|
|
||||||
" interactively)\n"
|
|
||||||
" (implies -r for safety"
|
|
||||||
" reasons)\n"
|
|
||||||
" -F, --reflash-full[=firmware] like -f, but don't preserve the"
|
|
||||||
" flash contents\n"
|
|
||||||
" in the area beyond the"
|
|
||||||
" firmware\n"
|
|
||||||
" -r, --reboot reboot on startup instead of"
|
|
||||||
" continuing from the\n"
|
|
||||||
" saved state in the config"
|
|
||||||
" file\n"
|
|
||||||
" -h, --help print this message and exit\n"
|
|
||||||
"The config file is formatted as INI file and contains the"
|
|
||||||
" settings for which\n"
|
|
||||||
"persistence makes sense, like calculator model, CPU"
|
|
||||||
" registers, etc.\n"
|
|
||||||
"If the config file is omitted, ~/.config/%s/config is used.\n"
|
|
||||||
"Please consult the manual for more details on config file"
|
|
||||||
" settings.\n",
|
|
||||||
progname, VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL, progname, DEFAULT_GDBSTUB_PORT, progname );
|
|
||||||
exit( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
static int action_debuglater( struct options* opt, struct option_def* match, char* this_opt, char* param, char* progname )
|
{"config", required_argument, NULL, 'c'},
|
||||||
{
|
|
||||||
char* end;
|
|
||||||
int port;
|
|
||||||
|
|
||||||
if ( param == NULL ) {
|
{"enable-debug", required_argument, NULL, 'D'},
|
||||||
if ( opt->debug_port == 0 )
|
{"debug", no_argument, NULL, 'd'},
|
||||||
opt->debug_port = DEFAULT_GDBSTUB_PORT;
|
{"reflash", required_argument, NULL, 'f'},
|
||||||
return false;
|
{"reflash-full", no_argument, NULL, 'F'},
|
||||||
}
|
{"reboot", no_argument, NULL, 'r'},
|
||||||
|
|
||||||
port = strtoul( param, &end, 0 );
|
{0, 0, 0, 0 }
|
||||||
if ( ( end == param ) || ( *end != '\0' ) ) {
|
};
|
||||||
fprintf( stderr, "Invalid port \"%s\", using default\n", param );
|
|
||||||
if ( opt->debug_port == 0 )
|
|
||||||
opt->debug_port = DEFAULT_GDBSTUB_PORT;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( opt->debug_port != 0 && opt->debug_port != DEFAULT_GDBSTUB_PORT )
|
while ( c != EOF ) {
|
||||||
fprintf( stderr,
|
c = getopt_long( argc, argv, optstring, long_options, &option_index );
|
||||||
"Additional debug port \"%s\" specified,"
|
|
||||||
" overriding\n",
|
|
||||||
param );
|
|
||||||
opt->debug_port = port;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int action_debug( struct options* opt, struct option_def* match, char* this_opt, char* param, char* progname )
|
switch ( c ) {
|
||||||
{
|
case 'h':
|
||||||
opt->start_debugger = true;
|
fprintf( stderr,
|
||||||
return action_debuglater( opt, match, this_opt, param, progname );
|
"%s %i.%i.%i Emulator for HP 49G+ / 50G calculators\n"
|
||||||
}
|
"Usage: %s [<options>] [<config-file>]\n"
|
||||||
|
"Valid options:\n"
|
||||||
|
" -c, --config[=<filename>] alternate config file\n"
|
||||||
|
" -D, --enable-debug[=<port>] enable the debugger interface\n"
|
||||||
|
" (default port: %u)\n"
|
||||||
|
" -d, --debug use along -D to also start the"
|
||||||
|
" debugger immediately\n"
|
||||||
|
" -f, --reflash[=firmware] rebuild the flash using the"
|
||||||
|
" supplied firmware\n"
|
||||||
|
" (default: select one"
|
||||||
|
" interactively)\n"
|
||||||
|
" (implies -r for safety"
|
||||||
|
" reasons)\n"
|
||||||
|
" -F, --reflash-full use along -f to drop the"
|
||||||
|
" flash contents\n"
|
||||||
|
" in the area beyond the"
|
||||||
|
" firmware\n"
|
||||||
|
" -r, --reboot reboot on startup instead of"
|
||||||
|
" continuing from the\n"
|
||||||
|
" saved state in the config"
|
||||||
|
" file\n"
|
||||||
|
" -h, --help print this message and exit\n"
|
||||||
|
"The config file is formatted as INI file and contains the"
|
||||||
|
" settings for which\n"
|
||||||
|
"persistence makes sense, like calculator model, CPU"
|
||||||
|
" registers, etc.\n"
|
||||||
|
"If the config file is omitted, ~/.config/%s/config is used.\n"
|
||||||
|
"Please consult the manual for more details on config file"
|
||||||
|
" settings.\n",
|
||||||
|
progname, VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL, progname, DEFAULT_GDBSTUB_PORT, progname );
|
||||||
|
exit( EXIT_SUCCESS );
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
if ( opt.reinit < X49GP_REINIT_REBOOT_ONLY )
|
||||||
|
opt.reinit = X49GP_REINIT_REBOOT_ONLY;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
opt.config = strdup( optarg );
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
{
|
||||||
|
char* end;
|
||||||
|
int port;
|
||||||
|
|
||||||
static int action_reinit_flash( struct options* opt, struct option_def* match, char* this_opt, char* param, char* progname )
|
if ( optarg == NULL && opt.debug_port == 0 )
|
||||||
{
|
opt.debug_port = DEFAULT_GDBSTUB_PORT;
|
||||||
if ( opt->reinit < X49GP_REINIT_FLASH )
|
|
||||||
opt->reinit = X49GP_REINIT_FLASH;
|
|
||||||
|
|
||||||
if ( param == NULL )
|
port = strtoul( optarg, &end, 0 );
|
||||||
return false;
|
if ( ( end == optarg ) || ( *end != '\0' ) ) {
|
||||||
|
fprintf( stderr, "Invalid port \"%s\", using default\n", optarg );
|
||||||
if ( opt->firmware != NULL )
|
if ( opt.debug_port == 0 )
|
||||||
fprintf( stderr,
|
opt.debug_port = DEFAULT_GDBSTUB_PORT;
|
||||||
"Additional firmware file \"%s\" specified,"
|
|
||||||
" overriding\n",
|
|
||||||
param );
|
|
||||||
opt->firmware = param;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int action_reinit_flash_full( struct options* opt, struct option_def* match, char* this_opt, char* param, char* progname )
|
|
||||||
{
|
|
||||||
int result = action_reinit_flash( opt, match, this_opt, param, progname );
|
|
||||||
opt->reinit = X49GP_REINIT_FLASH_FULL;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int action_reboot( struct options* opt, struct option_def* match, char* this_opt, char* param, char* progname )
|
|
||||||
{
|
|
||||||
if ( param != NULL )
|
|
||||||
warn_unneeded_param( match, this_opt );
|
|
||||||
|
|
||||||
if ( opt->reinit < X49GP_REINIT_REBOOT_ONLY )
|
|
||||||
opt->reinit = X49GP_REINIT_REBOOT_ONLY;
|
|
||||||
return param != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int action_longopt( struct options* opt, struct option_def* match, char* this_opt, char* param, char* progname )
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
char *test_str, *option_str;
|
|
||||||
|
|
||||||
if ( this_opt[ 1 ] != '-' || param != NULL ) {
|
|
||||||
fprintf( stderr, "Unrecognized option '-', ignoring\n" );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( i = 0; i < sizeof( option_defs ) / sizeof( option_defs[ 0 ] ); i++ ) {
|
|
||||||
if ( option_defs[ i ].longname == NULL )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
test_str = option_defs[ i ].longname;
|
|
||||||
option_str = this_opt + 2;
|
|
||||||
|
|
||||||
while ( *test_str != '\0' && *test_str == *option_str ) {
|
|
||||||
test_str++;
|
|
||||||
option_str++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( *test_str != '\0' )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
switch ( *option_str ) {
|
|
||||||
case '\0':
|
|
||||||
( option_defs[ i ].action )( opt, option_defs + i, this_opt, NULL, progname );
|
|
||||||
return true;
|
|
||||||
case '=':
|
|
||||||
( option_defs[ i ].action )( opt, option_defs + i, this_opt, option_str + 1, progname );
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf( stderr, "Unrecognized option \"%s\", ignoring\n", this_opt + 2 );
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int action_unknown_with_param( struct options* opt, struct option_def* match, char* this_opt, char* param, char* progname )
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int action_endopt( struct options* opt, struct option_def* match, char* this_opt, char* param, char* progname )
|
|
||||||
{
|
|
||||||
opt->more_options = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void parse_shortopt( struct options* opt, char* this_opt, char* progname )
|
|
||||||
{
|
|
||||||
char* option = this_opt + 1;
|
|
||||||
char* param;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if ( *option == '\0' ) {
|
|
||||||
fprintf( stderr, "Empty option present, ignoring\n" );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
for ( i = 0; i < sizeof( option_defs ) / sizeof( option_defs[ 0 ] ); i++ ) {
|
|
||||||
|
|
||||||
if ( *option == option_defs[ i ].shortname ) {
|
|
||||||
if ( *( option + 1 ) == '=' ) {
|
|
||||||
param = option + 2;
|
|
||||||
} else {
|
|
||||||
param = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ( option_defs[ i ].action )( opt, option_defs + i, this_opt, param, progname ) )
|
if ( opt.debug_port != 0 && opt.debug_port != DEFAULT_GDBSTUB_PORT )
|
||||||
return;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( i == sizeof( option_defs ) / sizeof( option_defs[ 0 ] ) )
|
|
||||||
fprintf( stderr, "Unrecognized option '%c', ignoring\n", *option );
|
|
||||||
option++;
|
|
||||||
} while ( *option != '\0' );
|
|
||||||
}
|
|
||||||
|
|
||||||
static void parse_options( struct options* opt, int argc, char** argv, char* progname )
|
|
||||||
{
|
|
||||||
opt->more_options = true;
|
|
||||||
|
|
||||||
while ( argc > 1 ) {
|
|
||||||
switch ( argv[ 1 ][ 0 ] ) {
|
|
||||||
case '\0':
|
|
||||||
break;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '-':
|
|
||||||
if ( opt->more_options ) {
|
|
||||||
parse_shortopt( opt, argv[ 1 ], progname );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* FALL THROUGH */
|
|
||||||
|
|
||||||
default:
|
|
||||||
if ( opt->config != NULL ) {
|
|
||||||
fprintf( stderr,
|
fprintf( stderr,
|
||||||
"Additional config file \"%s\""
|
"Additional debug port \"%s\" specified,"
|
||||||
" specified, overriding\n",
|
" overriding\n",
|
||||||
argv[ 1 ] );
|
optarg );
|
||||||
}
|
opt.debug_port = port;
|
||||||
opt->config = argv[ 1 ];
|
}
|
||||||
}
|
break;
|
||||||
|
case 'd':
|
||||||
|
opt.start_debugger = true;
|
||||||
|
break;
|
||||||
|
case 'F':
|
||||||
|
opt.reinit = X49GP_REINIT_FLASH_FULL;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
if ( opt.reinit < X49GP_REINIT_FLASH )
|
||||||
|
opt.reinit = X49GP_REINIT_FLASH;
|
||||||
|
|
||||||
argc--;
|
if ( opt.firmware != NULL )
|
||||||
argv++;
|
fprintf( stderr,
|
||||||
|
"Additional firmware file \"%s\" specified,"
|
||||||
|
" overriding\n",
|
||||||
|
optarg );
|
||||||
|
opt.firmware = optarg;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/************/
|
||||||
|
/* \OPTIONS */
|
||||||
|
/************/
|
||||||
|
|
||||||
void ui_sighnd( int sig )
|
void ui_sighnd( int sig )
|
||||||
{
|
{
|
||||||
|
@ -521,7 +381,6 @@ int main( int argc, char** argv )
|
||||||
{
|
{
|
||||||
char *progname, *progpath;
|
char *progname, *progpath;
|
||||||
int error;
|
int error;
|
||||||
struct options opt;
|
|
||||||
const char* home;
|
const char* home;
|
||||||
|
|
||||||
progname = g_path_get_basename( argv[ 0 ] );
|
progname = g_path_get_basename( argv[ 0 ] );
|
||||||
|
@ -529,12 +388,7 @@ int main( int argc, char** argv )
|
||||||
|
|
||||||
gtk_init( &argc, &argv );
|
gtk_init( &argc, &argv );
|
||||||
|
|
||||||
opt.config = NULL;
|
config_init( progname, argc, argv );
|
||||||
opt.debug_port = 0;
|
|
||||||
opt.start_debugger = false;
|
|
||||||
opt.reinit = X49GP_REINIT_NONE;
|
|
||||||
opt.firmware = NULL;
|
|
||||||
parse_options( &opt, argc, argv, progname );
|
|
||||||
|
|
||||||
x49gp = malloc( sizeof( x49gp_t ) );
|
x49gp = malloc( sizeof( x49gp_t ) );
|
||||||
if ( NULL == x49gp ) {
|
if ( NULL == x49gp ) {
|
||||||
|
|
Loading…
Reference in a new issue