diff --git a/src/emu/info.c b/src/emu/info.c index 2503cecd59a..71f499f804b 100644 --- a/src/emu/info.c +++ b/src/emu/info.c @@ -846,7 +846,7 @@ static void print_game_info(FILE *out, const game_driver *game) /* temporary hook until MESS device transition is complete */ mess_devices_setup(config, game); #endif /* MESS */ - portconfig = input_port_config_alloc(game->ipt); + portconfig = input_port_config_alloc(game->ipt, NULL, 0); /* print the header and the game name */ fprintf(out, "\t<" XML_TOP); diff --git a/src/emu/inptport.c b/src/emu/inptport.c index d2d901c3ab3..e42ca7b3cc7 100644 --- a/src/emu/inptport.c +++ b/src/emu/inptport.c @@ -101,6 +101,7 @@ #include "deprecat.h" #include #include +#include #ifdef MESS #include "inputx.h" @@ -481,7 +482,7 @@ static void frame_update_analog_field(analog_field_state *analog); static int frame_get_digital_field_state(const input_field_config *field); /* port configuration helpers */ -static input_port_config *port_config_detokenize(input_port_config *listhead, const input_port_token *ipt); +static input_port_config *port_config_detokenize(input_port_config *listhead, const input_port_token *ipt, char *errorbuf, int errorbuflen); static input_port_config *port_config_alloc(const input_port_config **listhead); static void port_config_free(const input_port_config **portptr); static input_port_config *port_config_find(const input_port_config *listhead, const char *tag); @@ -489,7 +490,7 @@ static input_field_config *field_config_alloc(input_port_config *port, int type, static void field_config_free(input_field_config **fieldptr); static input_setting_config *setting_config_alloc(input_field_config *field, input_port_value value, const char *name); static void setting_config_free(input_setting_config **settingptr); -static const input_field_diplocation *diplocation_list_alloc(const input_field_config *field, const char *location); +static const input_field_diplocation *diplocation_list_alloc(const input_field_config *field, const char *location, char *errorbuf, int errorbuflen); static void diplocation_free(input_field_diplocation **diplocptr); /* tokenization helpers */ @@ -596,6 +597,26 @@ INLINE int get_port_index(const input_port_config *portlist, const char *tag) } +/*------------------------------------------------- + error_buf_append - append text to an error + buffer +-------------------------------------------------*/ + +INLINE void *error_buf_append(char *errorbuf, int errorbuflen, const char *format, ...) +{ + int curlen = strlen(errorbuf); + int bytesleft = errorbuflen - curlen; + va_list va; + + va_start(va, format); + if (strlen(format) + 25 < bytesleft) + vsprintf(&errorbuf[curlen], format, va); + va_end(va); + + return NULL; +} + + /*************************************************************************** CORE SYSTEM MANAGEMENT @@ -609,6 +630,7 @@ INLINE int get_port_index(const input_port_config *portlist, const char *tag) time_t input_port_init(running_machine *machine, const input_port_token *tokens) { input_port_private *portdata; + char errorbuf[1024]; time_t basetime; /* allocate memory for our data structure */ @@ -626,7 +648,11 @@ time_t input_port_init(running_machine *machine, const input_port_token *tokens) /* if we have a token list, proceed */ if (tokens != NULL) { - machine->portconfig = input_port_config_alloc(tokens); + machine->portconfig = input_port_config_alloc(tokens, errorbuf, sizeof(errorbuf)); + if (errorbuf[0] != 0) + mame_printf_error("Input port errors:\n%s", errorbuf); + if (machine->portconfig == NULL) + fatalerror("Unable to construct input ports!"); init_port_state(machine); } @@ -668,14 +694,16 @@ static void input_port_exit(running_machine *machine) input ports from the given token list -------------------------------------------------*/ -const input_port_config *input_port_config_alloc(const input_port_token *tokens) +const input_port_config *input_port_config_alloc(const input_port_token *tokens, char *errorbuf, int errorbuflen) { - return port_config_detokenize(NULL, tokens); + if (errorbuf != NULL) + *errorbuf = 0; + return port_config_detokenize(NULL, tokens, errorbuf, errorbuflen); } /*------------------------------------------------- - input_port_config_alloc - free memory + input_port_config_free - free memory allocated from input_port_alloc -------------------------------------------------*/ @@ -2312,12 +2340,13 @@ static int frame_get_digital_field_state(const input_field_config *field) detokenize a series of input port tokens -------------------------------------------------*/ -static input_port_config *port_config_detokenize(input_port_config *listhead, const input_port_token *ipt) +static input_port_config *port_config_detokenize(input_port_config *listhead, const input_port_token *ipt, char *errorbuf, int errorbuflen) { UINT32 entrytype = INPUT_TOKEN_INVALID; input_setting_config *cursetting = NULL; input_field_config *curfield = NULL; input_port_config *curport = NULL; + input_port_value maskbits = 0; /* loop over tokens until we hit the end */ while (entrytype != INPUT_TOKEN_END) @@ -2338,7 +2367,7 @@ static input_port_config *port_config_detokenize(input_port_config *listhead, co /* including */ case INPUT_TOKEN_INCLUDE: - listhead = port_config_detokenize(listhead, TOKEN_GET_PTR(ipt, tokenptr)); + listhead = port_config_detokenize(listhead, TOKEN_GET_PTR(ipt, tokenptr), errorbuf, errorbuflen); break; /* start of a new input port */ @@ -2349,6 +2378,7 @@ static input_port_config *port_config_detokenize(input_port_config *listhead, co curport->tag = TOKEN_GET_STRING(ipt); curfield = NULL; cursetting = NULL; + maskbits = 0; break; /* modify an existing port */ @@ -2358,23 +2388,30 @@ static input_port_config *port_config_detokenize(input_port_config *listhead, co /* input field definition */ case INPUT_TOKEN_FIELD: - if (curport == NULL) - fatalerror("INPUT_TOKEN_FIELD encountered with no active port"); - TOKEN_UNGET_UINT32(ipt); TOKEN_GET_UINT32_UNPACK2(ipt, entrytype, 8, type, 24); TOKEN_GET_UINT64_UNPACK2(ipt, mask, 32, defval, 32); + if (curport == NULL) + return error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_FIELD encountered with no active port (mask=%X defval=%X)\n", mask, defval); + if ((maskbits & mask) != 0) + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_FIELD specifies duplicate port bits (mask=%X)\n", mask); + maskbits |= mask; + curfield = field_config_alloc(curport, type, defval, mask); cursetting = NULL; break; /* field or setting condition */ case INPUT_TOKEN_CONDITION: - if (curfield == NULL && cursetting == NULL) - fatalerror("INPUT_TOKEN_CONDITION encountered with no active field or setting"); - TOKEN_UNGET_UINT32(ipt); + if (curfield == NULL && cursetting == NULL) + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_CONDITION encountered with no active field or setting\n"); + TOKEN_SKIP_UINT32(ipt); + TOKEN_SKIP_UINT64(ipt); + break; + } TOKEN_GET_UINT32_UNPACK2(ipt, entrytype, 8, condition.condition, 24); TOKEN_GET_UINT64_UNPACK2(ipt, condition.mask, 32, condition.value, 32); condition.tag = TOKEN_GET_STRING(ipt); @@ -2395,74 +2432,108 @@ static input_port_config *port_config_detokenize(input_port_config *listhead, co case INPUT_TOKEN_PLAYER7: case INPUT_TOKEN_PLAYER8: if (curfield == NULL) - fatalerror("INPUT_TOKEN_PLAYERn encountered with no active field"); + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_PLAYERn encountered with no active field\n"); + break; + } curfield->player = entrytype - INPUT_TOKEN_PLAYER1; break; /* field category */ case INPUT_TOKEN_CATEGORY: - if (curfield == NULL) - fatalerror("INPUT_TOKEN_CATEGORY encountered with no active field"); TOKEN_UNGET_UINT32(ipt); + if (curfield == NULL) + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_CATEGORY encountered with no active field\n"); + TOKEN_SKIP_UINT32(ipt); + break; + } TOKEN_GET_UINT32_UNPACK2(ipt, entrytype, 8, curfield->category, 24); break; /* field flags */ case INPUT_TOKEN_UNUSED: if (curfield == NULL) - fatalerror("INPUT_TOKEN_UNUSED encountered with no active field"); + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_UNUSED encountered with no active field\n"); + break; + } curfield->flags |= FIELD_FLAG_UNUSED; break; case INPUT_TOKEN_COCKTAIL: if (curfield == NULL) - fatalerror("INPUT_TOKEN_COCKTAIL encountered with no active field"); + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_COCKTAIL encountered with no active field\n"); + break; + } curfield->flags |= FIELD_FLAG_COCKTAIL; curfield->player = 1; break; case INPUT_TOKEN_ROTATED: if (curfield == NULL) - fatalerror("INPUT_TOKEN_ROTATED encountered with no active field"); + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_ROTATED encountered with no active field\n"); + break; + } curfield->flags |= FIELD_FLAG_ROTATED; break; case INPUT_TOKEN_TOGGLE: if (curfield == NULL) - fatalerror("INPUT_TOKEN_TOGGLE encountered with no active field"); + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_TOGGLE encountered with no active field\n"); + break; + } curfield->flags |= FIELD_FLAG_TOGGLE; break; /* field impulse */ case INPUT_TOKEN_IMPULSE: - if (curfield == NULL) - fatalerror("INPUT_TOKEN_IMPULSE encountered with no active field"); TOKEN_UNGET_UINT32(ipt); + if (curfield == NULL) + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_IMPULSE encountered with no active field\n"); + TOKEN_SKIP_UINT32(ipt); + break; + } TOKEN_GET_UINT32_UNPACK2(ipt, entrytype, 8, curfield->impulse, 24); break; /* field name */ case INPUT_TOKEN_NAME: if (curfield == NULL) - fatalerror("INPUT_TOKEN_NAME encountered with no active field"); + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_NAME encountered with no active field\n"); + TOKEN_SKIP_STRING(ipt); + break; + } curfield->name = input_port_string_from_token(*ipt++); break; /* field code sequence */ case INPUT_TOKEN_CODE: - if (curfield == NULL) - fatalerror("INPUT_TOKEN_CODE encountered with no active field"); - TOKEN_UNGET_UINT32(ipt); + if (curfield == NULL) + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_CODE encountered with no active field\n"); + TOKEN_SKIP_UINT64(ipt); + break; + } TOKEN_GET_UINT64_UNPACK2(ipt, entrytype, 8, val, 32); - input_seq_append_or(&curfield->seq[SEQ_TYPE_STANDARD], val); break; /* field custom callback */ case INPUT_TOKEN_CUSTOM: if (curfield == NULL) - fatalerror("INPUT_TOKEN_CUSTOM encountered with no active field"); + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_CUSTOM encountered with no active field\n"); + TOKEN_SKIP_PTR(ipt); + TOKEN_SKIP_PTR(ipt); + break; + } curfield->custom = TOKEN_GET_PTR(ipt, customptr); curfield->custom_param = (void *)TOKEN_GET_PTR(ipt, voidptr); break; @@ -2470,7 +2541,12 @@ static input_port_config *port_config_detokenize(input_port_config *listhead, co /* field changed callback */ case INPUT_TOKEN_CHANGED: if (curfield == NULL) - fatalerror("INPUT_TOKEN_CHANGED encountered with no active field"); + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_CHANGED encountered with no active field\n"); + TOKEN_SKIP_PTR(ipt); + TOKEN_SKIP_PTR(ipt); + break; + } curfield->changed = TOKEN_GET_PTR(ipt, changedptr); curfield->changed_param = (void *)TOKEN_GET_PTR(ipt, voidptr); break; @@ -2478,8 +2554,12 @@ static input_port_config *port_config_detokenize(input_port_config *listhead, co /* DIP switch location */ case INPUT_TOKEN_DIPLOCATION: if (curfield == NULL) - fatalerror("INPUT_TOKEN_DIPLOCATION encountered with no active field"); - curfield->diploclist = diplocation_list_alloc(curfield, TOKEN_GET_STRING(ipt)); + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_DIPLOCATION encountered with no active field\n"); + TOKEN_SKIP_STRING(ipt); + break; + } + curfield->diploclist = diplocation_list_alloc(curfield, TOKEN_GET_STRING(ipt), errorbuf, errorbuflen); break; /* joystick flags */ @@ -2488,18 +2568,23 @@ static input_port_config *port_config_detokenize(input_port_config *listhead, co case INPUT_TOKEN_8WAY: case INPUT_TOKEN_16WAY: if (curfield == NULL) - fatalerror("INPUT_TOKEN_nWAY encountered with no active field"); + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_nWAY encountered with no active field\n"); + break; + } curfield->way = 2 << (entrytype - INPUT_TOKEN_2WAY); break; /* (MESS) natural keyboard support */ case INPUT_TOKEN_CHAR: - if (curfield == NULL) - fatalerror("INPUT_TOKEN_CHAR encountered with no active field"); - TOKEN_UNGET_UINT32(ipt); + if (curfield == NULL) + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_CHAR encountered with no active field\n"); + TOKEN_SKIP_UINT64(ipt); + break; + } TOKEN_GET_UINT64_UNPACK2(ipt, entrytype, 8, val, 32); - for (index = 0; index < ARRAY_LENGTH(curfield->chars); index++) if (curfield->chars[index] == 0) { @@ -2511,69 +2596,97 @@ static input_port_config *port_config_detokenize(input_port_config *listhead, co /* analog minimum/maximum */ case INPUT_TOKEN_MINMAX: if (curfield == NULL) - fatalerror("INPUT_TOKEN_MINMAX encountered with no active field"); + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_MINMAX encountered with no active field\n"); + TOKEN_SKIP_UINT64(ipt); + break; + } TOKEN_GET_UINT64_UNPACK2(ipt, curfield->min, 32, curfield->max, 32); break; /* analog sensitivity */ case INPUT_TOKEN_SENSITIVITY: - if (curfield == NULL) - fatalerror("INPUT_TOKEN_SENSITIVITY encountered with no active field"); TOKEN_UNGET_UINT32(ipt); + if (curfield == NULL) + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_SENSITIVITY encountered with no active field\n"); + TOKEN_SKIP_UINT32(ipt); + break; + } TOKEN_GET_UINT32_UNPACK2(ipt, entrytype, 8, curfield->sensitivity, 24); break; /* analog keyboard delta */ case INPUT_TOKEN_KEYDELTA: - if (curfield == NULL) - fatalerror("INPUT_TOKEN_KEYDELTA encountered with no active field"); TOKEN_UNGET_UINT32(ipt); + if (curfield == NULL) + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_KEYDELTA encountered with no active field\n"); + TOKEN_SKIP_UINT32(ipt); + break; + } TOKEN_GET_UINT32_UNPACK2(ipt, entrytype, 8, curfield->delta, -24); curfield->centerdelta = curfield->delta; break; /* analog autocenter delta */ case INPUT_TOKEN_CENTERDELTA: - if (curfield == NULL) - fatalerror("INPUT_TOKEN_CENTERDELTA encountered with no active field"); TOKEN_UNGET_UINT32(ipt); + if (curfield == NULL) + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_CENTERDELTA encountered with no active field\n"); + TOKEN_SKIP_UINT32(ipt); + break; + } TOKEN_GET_UINT32_UNPACK2(ipt, entrytype, 8, curfield->centerdelta, -24); break; /* analog reverse flags */ case INPUT_TOKEN_REVERSE: if (curfield == NULL) - fatalerror("INPUT_TOKEN_REVERSE encountered with no active field"); + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_REVERSE encountered with no active field\n"); + break; + } curfield->flags |= ANALOG_FLAG_REVERSE; break; case INPUT_TOKEN_RESET: if (curfield == NULL) - fatalerror("INPUT_TOKEN_RESET encountered with no active field"); + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_RESET encountered with no active field\n"); + break; + } curfield->flags |= ANALOG_FLAG_RESET; break; case INPUT_TOKEN_WRAPS: if (curfield == NULL) - fatalerror("INPUT_TOKEN_WRAPS encountered with no active field"); + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_WRAPS encountered with no active field\n"); curfield->flags |= ANALOG_FLAG_WRAPS; break; case INPUT_TOKEN_INVERT: if (curfield == NULL) - fatalerror("INPUT_TOKEN_INVERT encountered with no active field"); + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_INVERT encountered with no active field\n"); + break; + } curfield->flags |= ANALOG_FLAG_INVERT; break; /* analog crosshair parameters */ case INPUT_TOKEN_CROSSHAIR: - if (curfield == NULL) - fatalerror("INPUT_TOKEN_CROSSHAIR encountered with no active field"); - TOKEN_UNGET_UINT32(ipt); + if (curfield == NULL) + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_CROSSHAIR encountered with no active field\n"); + TOKEN_SKIP_UINT32(ipt); + TOKEN_SKIP_UINT64(ipt); + break; + } TOKEN_GET_UINT32_UNPACK3(ipt, entrytype, 8, curfield->crossaxis, 4, curfield->crossaltaxis, -20); TOKEN_GET_UINT64_UNPACK2(ipt, curfield->crossscale, -32, curfield->crossoffset, -32); - curfield->crossaltaxis *= 1.0f / 65536.0f; curfield->crossscale *= 1.0f / 65536.0f; curfield->crossoffset *= 1.0f / 65536.0f; @@ -2581,83 +2694,110 @@ static input_port_config *port_config_detokenize(input_port_config *listhead, co /* analog decrement sequence */ case INPUT_TOKEN_CODE_DEC: - if (curfield == NULL) - fatalerror("INPUT_TOKEN_CODE_DEC encountered with no active field"); - index = entrytype - INPUT_TOKEN_CODE; - TOKEN_UNGET_UINT32(ipt); + if (curfield == NULL) + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_CODE_DEC encountered with no active field\n"); + TOKEN_SKIP_UINT64(ipt); + break; + } + index = entrytype - INPUT_TOKEN_CODE; TOKEN_GET_UINT64_UNPACK2(ipt, entrytype, 8, val, 32); - input_seq_append_or(&curfield->seq[SEQ_TYPE_DECREMENT], val); break; /* analog increment sequence */ case INPUT_TOKEN_CODE_INC: - if (curfield == NULL) - fatalerror("INPUT_TOKEN_CODE_INC encountered with no active field"); - index = entrytype - INPUT_TOKEN_CODE; - TOKEN_UNGET_UINT32(ipt); + if (curfield == NULL) + { + TOKEN_SKIP_UINT64(ipt); + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_CODE_INC encountered with no active field\n"); + break; + } + index = entrytype - INPUT_TOKEN_CODE; TOKEN_GET_UINT64_UNPACK2(ipt, entrytype, 8, val, 32); - input_seq_append_or(&curfield->seq[SEQ_TYPE_INCREMENT], val); break; /* analog wraps flag */ case INPUT_TOKEN_FULL_TURN_COUNT: - if (curfield == NULL) - fatalerror("INPUT_TOKEN_FULL_TURN_COUNT encountered with no active field"); TOKEN_UNGET_UINT32(ipt); + if (curfield == NULL) + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_FULL_TURN_COUNT encountered with no active field\n"); + TOKEN_SKIP_UINT32(ipt); + break; + } TOKEN_GET_UINT32_UNPACK2(ipt, entrytype, 8, curfield->full_turn_count, 24); break; case INPUT_TOKEN_POSITIONS: - if (curfield == NULL) - fatalerror("INPUT_TOKEN_POSITIONS encountered with no active field"); TOKEN_UNGET_UINT32(ipt); + if (curfield == NULL) + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_POSITIONS encountered with no active field\n"); + TOKEN_SKIP_UINT32(ipt); + break; + } TOKEN_GET_UINT32_UNPACK2(ipt, entrytype, 8, curfield->max, 24); break; case INPUT_TOKEN_REMAP_TABLE: if (curfield == NULL) - fatalerror("INPUT_TOKEN_REMAP_TABLE encountered with no active field"); + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_REMAP_TABLE encountered with no active field\n"); + TOKEN_SKIP_PTR(ipt); + break; + } curfield->remap_table = TOKEN_GET_PTR(ipt, ui32ptr); break; /* DIP switch definition */ case INPUT_TOKEN_DIPNAME: if (curport == NULL) - fatalerror("INPUT_TOKEN_DIPNAME encountered with no active port"); - + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_DIPNAME encountered with no active port\n"); + TOKEN_SKIP_UINT64(ipt); + TOKEN_SKIP_STRING(ipt); + break; + } TOKEN_GET_UINT64_UNPACK2(ipt, mask, 32, defval, 32); - curfield = field_config_alloc(curport, IPT_DIPSWITCH, defval, mask); cursetting = NULL; - curfield->name = input_port_string_from_token(*ipt++); break; /* DIP switch setting */ case INPUT_TOKEN_DIPSETTING: - if (curfield == NULL) - fatalerror("INPUT_TOKEN_DIPSETTING encountered with no active field"); - TOKEN_UNGET_UINT32(ipt); + if (curfield == NULL) + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_DIPSETTING encountered with no active field\n"); + TOKEN_SKIP_UINT64(ipt); + TOKEN_SKIP_STRING(ipt); + break; + } TOKEN_GET_UINT64_UNPACK2(ipt, entrytype, 8, defval, 32); - cursetting = setting_config_alloc(curfield, defval & curfield->mask, input_port_string_from_token(*ipt++)); break; /* special DIP switch with on/off values */ case INPUT_TOKEN_SPECIAL_ONOFF: - if (curport == NULL) - fatalerror("INPUT_TOKEN_SPECIAL_ONOFF encountered with no active port"); - TOKEN_UNGET_UINT32(ipt); TOKEN_GET_UINT32_UNPACK3(ipt, entrytype, 8, hasdiploc, 1, temptoken.i, 23); TOKEN_GET_UINT64_UNPACK2(ipt, mask, 32, defval, 32); + if (curport == NULL) + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_SPECIAL_ONOFF encountered with no active port\n"); + TOKEN_SKIP_UINT32(ipt); + TOKEN_SKIP_UINT64(ipt); + if (hasdiploc) + TOKEN_SKIP_STRING(ipt); + break; + } curfield = field_config_alloc(curport, IPT_DIPSWITCH, defval, mask); cursetting = NULL; @@ -2668,7 +2808,7 @@ static input_port_config *port_config_detokenize(input_port_config *listhead, co curfield->seq[SEQ_TYPE_STANDARD].code[0] = KEYCODE_F2; } if (hasdiploc) - curfield->diploclist = diplocation_list_alloc(curfield, TOKEN_GET_STRING(ipt)); + curfield->diploclist = diplocation_list_alloc(curfield, TOKEN_GET_STRING(ipt), errorbuf, errorbuflen); temptoken.i = INPUT_STRING_Off; cursetting = setting_config_alloc(curfield, defval & mask, input_port_string_from_token(temptoken)); @@ -2680,67 +2820,79 @@ static input_port_config *port_config_detokenize(input_port_config *listhead, co /* configuration definition */ case INPUT_TOKEN_CONFNAME: if (curport == NULL) - fatalerror("INPUT_TOKEN_CONFNAME encountered with no active port"); - + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_CONFNAME encountered with no active port\n"); + TOKEN_SKIP_UINT64(ipt); + TOKEN_SKIP_STRING(ipt); + break; + } TOKEN_GET_UINT64_UNPACK2(ipt, mask, 32, defval, 32); - curfield = field_config_alloc(curport, IPT_CONFIG, defval, mask); cursetting = NULL; - curfield->name = input_port_string_from_token(*ipt++); break; /* configuration setting */ case INPUT_TOKEN_CONFSETTING: - if (curfield == NULL) - fatalerror("INPUT_TOKEN_CONFSETTING encountered with no active field"); - TOKEN_UNGET_UINT32(ipt); + if (curfield == NULL) + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_CONFSETTING encountered with no active field\n"); + TOKEN_SKIP_UINT64(ipt); + TOKEN_SKIP_STRING(ipt); + break; + } TOKEN_GET_UINT64_UNPACK2(ipt, entrytype, 8, defval, 32); - cursetting = setting_config_alloc(curfield, defval & curfield->mask, input_port_string_from_token(*ipt++)); break; /* configuration definition */ case INPUT_TOKEN_CATEGORY_NAME: if (curport == NULL) - fatalerror("INPUT_TOKEN_CATEGORY_NAME encountered with no active port"); - + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_CATEGORY_NAME encountered with no active port\n"); + TOKEN_SKIP_UINT64(ipt); + TOKEN_SKIP_STRING(ipt); + break; + } TOKEN_GET_UINT64_UNPACK2(ipt, mask, 32, defval, 32); - curfield = field_config_alloc(curport, IPT_CATEGORY, defval, mask); cursetting = NULL; - curfield->name = input_port_string_from_token(*ipt++); break; /* configuration setting */ case INPUT_TOKEN_CATEGORY_SETTING: - if (curfield == NULL) - fatalerror("INPUT_TOKEN_CATEGORY_SETTING encountered with no active field"); - TOKEN_UNGET_UINT32(ipt); + if (curfield == NULL) + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_CATEGORY_SETTING encountered with no active field\n"); + TOKEN_SKIP_UINT64(ipt); + TOKEN_SKIP_STRING(ipt); + break; + } TOKEN_GET_UINT64_UNPACK2(ipt, entrytype, 8, defval, 32); - cursetting = setting_config_alloc(curfield, defval & curfield->mask, input_port_string_from_token(*ipt++)); break; /* analog adjuster definition */ case INPUT_TOKEN_ADJUSTER: - if (curport == NULL) - fatalerror("INPUT_TOKEN_ADJUSTER encountered with no active port"); - TOKEN_UNGET_UINT32(ipt); + if (curport == NULL) + { + error_buf_append(errorbuf, errorbuflen, "INPUT_TOKEN_ADJUSTER encountered with no active port\n"); + TOKEN_SKIP_UINT64(ipt); + TOKEN_SKIP_STRING(ipt); + break; + } TOKEN_GET_UINT64_UNPACK2(ipt, entrytype, 8, defval, 32); - curfield = field_config_alloc(curport, IPT_ADJUSTER, defval, 0xff); cursetting = NULL; - curfield->name = TOKEN_GET_STRING(ipt); break; default: - fatalerror("Invalid token %d in input ports\n", entrytype); + error_buf_append(errorbuf, errorbuflen, "Invalid token %d in input ports\n", entrytype); break; } } @@ -2949,7 +3101,7 @@ static void setting_config_free(input_setting_config **settingptr) descriptions -------------------------------------------------*/ -static const input_field_diplocation *diplocation_list_alloc(const input_field_config *field, const char *location) +static const input_field_diplocation *diplocation_list_alloc(const input_field_config *field, const char *location, char *errorbuf, int errorbuflen) { input_field_diplocation *head = NULL; input_field_diplocation **tailptr = &head; @@ -3001,7 +3153,10 @@ static const input_field_diplocation *diplocation_list_alloc(const input_field_c { char *namecopy; if (lastname == NULL) - fatalerror("Switch location '%s' missing switch name!", location); + { + error_buf_append(errorbuf, errorbuflen, "Switch location '%s' missing switch name!\n", location); + lastname = (char *)"UNK"; + } (*tailptr)->swname = namecopy = malloc_or_die(strlen(lastname) + 1); strcpy(namecopy, lastname); } @@ -3016,8 +3171,9 @@ static const input_field_diplocation *diplocation_list_alloc(const input_field_c /* now scan the switch number */ if (sscanf(number, "%d", &val) != 1) - fatalerror("Switch location '%s' has invalid format!", location); - (*tailptr)->swnum = val; + error_buf_append(errorbuf, errorbuflen, "Switch location '%s' has invalid format!\n", location); + else + (*tailptr)->swnum = val; /* advance to the next item */ curentry = comma; @@ -3030,7 +3186,7 @@ static const input_field_diplocation *diplocation_list_alloc(const input_field_c for (bits = 0, temp = field->mask; temp != 0 && bits < 32; bits++) temp &= temp - 1; if (bits != entries) - fatalerror("Switch location '%s' does not describe enough bits for mask %X\n", location, field->mask); + error_buf_append(errorbuf, errorbuflen, "Switch location '%s' does not describe enough bits for mask %X\n", location, field->mask); return head; } diff --git a/src/emu/inptport.h b/src/emu/inptport.h index 546fdbedced..286fe5dd61f 100644 --- a/src/emu/inptport.h +++ b/src/emu/inptport.h @@ -936,7 +936,7 @@ time_t input_port_init(running_machine *machine, const input_port_token *tokens) /* ----- port configurations ----- */ /* allocate a list of input ports from the given token list */ -const input_port_config *input_port_config_alloc(const input_port_token *tokens); +const input_port_config *input_port_config_alloc(const input_port_token *tokens, char *errorbuf, int errorbuflen); /* free memory allocated from input_port_alloc */ void input_port_config_free(const input_port_config *portlist); diff --git a/src/emu/tokenize.h b/src/emu/tokenize.h index f9e85f862b8..aaff8a6f73b 100644 --- a/src/emu/tokenize.h +++ b/src/emu/tokenize.h @@ -128,6 +128,12 @@ #define TOKEN_UNGET_UINT32(tp) ((tp)--) #define TOKEN_UNGET_UINT64(tp) ((tp) -= 8 / sizeof(FPTR)) +/* token skip primitives */ +#define TOKEN_SKIP_PTR(tp) ((tp)++) +#define TOKEN_SKIP_STRING(tp) ((tp)++) +#define TOKEN_SKIP_UINT32(tp) ((tp)++) +#define TOKEN_SKIP_UINT64(tp) ((tp) += 8 / sizeof(FPTR)) + /* extract a value from a fixed number of bits; if bits is negative, treat it as a signed value */ #define UNSHIFT_AND_MASK32(src, val, bits, shift) do { \ if ((bits) < 0) \ diff --git a/src/emu/validity.c b/src/emu/validity.c index f48031edc2b..b0141747d1d 100644 --- a/src/emu/validity.c +++ b/src/emu/validity.c @@ -1190,6 +1190,7 @@ static int validate_inputs(int drivnum, const machine_config *config) const input_field_config *field; const game_driver *driver = drivers[drivnum]; int empty_string_found = FALSE; + char errorbuf[1024]; quark_entry *entry; int error = FALSE; UINT32 crc; @@ -1208,7 +1209,9 @@ static int validate_inputs(int drivnum, const machine_config *config) quark_add(inputs_table, drivnum, crc); /* allocate the input ports */ - portlist = input_port_config_alloc(driver->ipt); + portlist = input_port_config_alloc(driver->ipt, errorbuf, sizeof(errorbuf)); + if (errorbuf[0] != 0) + mame_printf_error("%s: %s has input port errors:\n%s\n", driver->source_file, driver->name, errorbuf); /* check for duplicate tags */ for (port = portlist; port != NULL; port = port->next)