Added TOKEN_SKIP_* macros to tokenize.h.

Changed error reporting during input port detokenization to fill a buffer
rather than fatalerror-ing immediately. Should now properly skip over
any invalid tokens.

Enhanced error detection during input port detokenization to catch 
duplicate bits. There are a lot of these!

Updated initialization code to print errors and fatal only if the input
ports were unable to be constructed at all.
This commit is contained in:
Aaron Giles 2008-05-25 21:24:19 +00:00
parent 032c1ddaee
commit 67db0742f0
5 changed files with 274 additions and 109 deletions

View File

@ -846,7 +846,7 @@ static void print_game_info(FILE *out, const game_driver *game)
/* temporary hook until MESS device transition is complete */ /* temporary hook until MESS device transition is complete */
mess_devices_setup(config, game); mess_devices_setup(config, game);
#endif /* MESS */ #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 */ /* print the header and the game name */
fprintf(out, "\t<" XML_TOP); fprintf(out, "\t<" XML_TOP);

View File

@ -101,6 +101,7 @@
#include "deprecat.h" #include "deprecat.h"
#include <ctype.h> #include <ctype.h>
#include <time.h> #include <time.h>
#include <stdarg.h>
#ifdef MESS #ifdef MESS
#include "inputx.h" #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); static int frame_get_digital_field_state(const input_field_config *field);
/* port configuration helpers */ /* 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 input_port_config *port_config_alloc(const input_port_config **listhead);
static void port_config_free(const input_port_config **portptr); 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); 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 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 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 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); static void diplocation_free(input_field_diplocation **diplocptr);
/* tokenization helpers */ /* 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 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) time_t input_port_init(running_machine *machine, const input_port_token *tokens)
{ {
input_port_private *portdata; input_port_private *portdata;
char errorbuf[1024];
time_t basetime; time_t basetime;
/* allocate memory for our data structure */ /* 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 we have a token list, proceed */
if (tokens != NULL) 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); init_port_state(machine);
} }
@ -668,14 +694,16 @@ static void input_port_exit(running_machine *machine)
input ports from the given token list 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 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 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; UINT32 entrytype = INPUT_TOKEN_INVALID;
input_setting_config *cursetting = NULL; input_setting_config *cursetting = NULL;
input_field_config *curfield = NULL; input_field_config *curfield = NULL;
input_port_config *curport = NULL; input_port_config *curport = NULL;
input_port_value maskbits = 0;
/* loop over tokens until we hit the end */ /* loop over tokens until we hit the end */
while (entrytype != INPUT_TOKEN_END) while (entrytype != INPUT_TOKEN_END)
@ -2338,7 +2367,7 @@ static input_port_config *port_config_detokenize(input_port_config *listhead, co
/* including */ /* including */
case INPUT_TOKEN_INCLUDE: 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; break;
/* start of a new input port */ /* 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); curport->tag = TOKEN_GET_STRING(ipt);
curfield = NULL; curfield = NULL;
cursetting = NULL; cursetting = NULL;
maskbits = 0;
break; break;
/* modify an existing port */ /* modify an existing port */
@ -2358,23 +2388,30 @@ static input_port_config *port_config_detokenize(input_port_config *listhead, co
/* input field definition */ /* input field definition */
case INPUT_TOKEN_FIELD: case INPUT_TOKEN_FIELD:
if (curport == NULL)
fatalerror("INPUT_TOKEN_FIELD encountered with no active port");
TOKEN_UNGET_UINT32(ipt); TOKEN_UNGET_UINT32(ipt);
TOKEN_GET_UINT32_UNPACK2(ipt, entrytype, 8, type, 24); TOKEN_GET_UINT32_UNPACK2(ipt, entrytype, 8, type, 24);
TOKEN_GET_UINT64_UNPACK2(ipt, mask, 32, defval, 32); 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); curfield = field_config_alloc(curport, type, defval, mask);
cursetting = NULL; cursetting = NULL;
break; break;
/* field or setting condition */ /* field or setting condition */
case INPUT_TOKEN_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); 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_UINT32_UNPACK2(ipt, entrytype, 8, condition.condition, 24);
TOKEN_GET_UINT64_UNPACK2(ipt, condition.mask, 32, condition.value, 32); TOKEN_GET_UINT64_UNPACK2(ipt, condition.mask, 32, condition.value, 32);
condition.tag = TOKEN_GET_STRING(ipt); 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_PLAYER7:
case INPUT_TOKEN_PLAYER8: case INPUT_TOKEN_PLAYER8:
if (curfield == NULL) 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; curfield->player = entrytype - INPUT_TOKEN_PLAYER1;
break; break;
/* field category */ /* field category */
case INPUT_TOKEN_CATEGORY: case INPUT_TOKEN_CATEGORY:
if (curfield == NULL)
fatalerror("INPUT_TOKEN_CATEGORY encountered with no active field");
TOKEN_UNGET_UINT32(ipt); 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); TOKEN_GET_UINT32_UNPACK2(ipt, entrytype, 8, curfield->category, 24);
break; break;
/* field flags */ /* field flags */
case INPUT_TOKEN_UNUSED: case INPUT_TOKEN_UNUSED:
if (curfield == NULL) 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; curfield->flags |= FIELD_FLAG_UNUSED;
break; break;
case INPUT_TOKEN_COCKTAIL: case INPUT_TOKEN_COCKTAIL:
if (curfield == NULL) 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->flags |= FIELD_FLAG_COCKTAIL;
curfield->player = 1; curfield->player = 1;
break; break;
case INPUT_TOKEN_ROTATED: case INPUT_TOKEN_ROTATED:
if (curfield == NULL) 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; curfield->flags |= FIELD_FLAG_ROTATED;
break; break;
case INPUT_TOKEN_TOGGLE: case INPUT_TOKEN_TOGGLE:
if (curfield == NULL) 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; curfield->flags |= FIELD_FLAG_TOGGLE;
break; break;
/* field impulse */ /* field impulse */
case INPUT_TOKEN_IMPULSE: case INPUT_TOKEN_IMPULSE:
if (curfield == NULL)
fatalerror("INPUT_TOKEN_IMPULSE encountered with no active field");
TOKEN_UNGET_UINT32(ipt); 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); TOKEN_GET_UINT32_UNPACK2(ipt, entrytype, 8, curfield->impulse, 24);
break; break;
/* field name */ /* field name */
case INPUT_TOKEN_NAME: case INPUT_TOKEN_NAME:
if (curfield == NULL) 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++); curfield->name = input_port_string_from_token(*ipt++);
break; break;
/* field code sequence */ /* field code sequence */
case INPUT_TOKEN_CODE: case INPUT_TOKEN_CODE:
if (curfield == NULL)
fatalerror("INPUT_TOKEN_CODE encountered with no active field");
TOKEN_UNGET_UINT32(ipt); 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); TOKEN_GET_UINT64_UNPACK2(ipt, entrytype, 8, val, 32);
input_seq_append_or(&curfield->seq[SEQ_TYPE_STANDARD], val); input_seq_append_or(&curfield->seq[SEQ_TYPE_STANDARD], val);
break; break;
/* field custom callback */ /* field custom callback */
case INPUT_TOKEN_CUSTOM: case INPUT_TOKEN_CUSTOM:
if (curfield == NULL) 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 = TOKEN_GET_PTR(ipt, customptr);
curfield->custom_param = (void *)TOKEN_GET_PTR(ipt, voidptr); curfield->custom_param = (void *)TOKEN_GET_PTR(ipt, voidptr);
break; break;
@ -2470,7 +2541,12 @@ static input_port_config *port_config_detokenize(input_port_config *listhead, co
/* field changed callback */ /* field changed callback */
case INPUT_TOKEN_CHANGED: case INPUT_TOKEN_CHANGED:
if (curfield == NULL) 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 = TOKEN_GET_PTR(ipt, changedptr);
curfield->changed_param = (void *)TOKEN_GET_PTR(ipt, voidptr); curfield->changed_param = (void *)TOKEN_GET_PTR(ipt, voidptr);
break; break;
@ -2478,8 +2554,12 @@ static input_port_config *port_config_detokenize(input_port_config *listhead, co
/* DIP switch location */ /* DIP switch location */
case INPUT_TOKEN_DIPLOCATION: case INPUT_TOKEN_DIPLOCATION:
if (curfield == NULL) 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; break;
/* joystick flags */ /* 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_8WAY:
case INPUT_TOKEN_16WAY: case INPUT_TOKEN_16WAY:
if (curfield == NULL) 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); curfield->way = 2 << (entrytype - INPUT_TOKEN_2WAY);
break; break;
/* (MESS) natural keyboard support */ /* (MESS) natural keyboard support */
case INPUT_TOKEN_CHAR: case INPUT_TOKEN_CHAR:
if (curfield == NULL)
fatalerror("INPUT_TOKEN_CHAR encountered with no active field");
TOKEN_UNGET_UINT32(ipt); 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); TOKEN_GET_UINT64_UNPACK2(ipt, entrytype, 8, val, 32);
for (index = 0; index < ARRAY_LENGTH(curfield->chars); index++) for (index = 0; index < ARRAY_LENGTH(curfield->chars); index++)
if (curfield->chars[index] == 0) if (curfield->chars[index] == 0)
{ {
@ -2511,69 +2596,97 @@ static input_port_config *port_config_detokenize(input_port_config *listhead, co
/* analog minimum/maximum */ /* analog minimum/maximum */
case INPUT_TOKEN_MINMAX: case INPUT_TOKEN_MINMAX:
if (curfield == NULL) 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); TOKEN_GET_UINT64_UNPACK2(ipt, curfield->min, 32, curfield->max, 32);
break; break;
/* analog sensitivity */ /* analog sensitivity */
case INPUT_TOKEN_SENSITIVITY: case INPUT_TOKEN_SENSITIVITY:
if (curfield == NULL)
fatalerror("INPUT_TOKEN_SENSITIVITY encountered with no active field");
TOKEN_UNGET_UINT32(ipt); 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); TOKEN_GET_UINT32_UNPACK2(ipt, entrytype, 8, curfield->sensitivity, 24);
break; break;
/* analog keyboard delta */ /* analog keyboard delta */
case INPUT_TOKEN_KEYDELTA: case INPUT_TOKEN_KEYDELTA:
if (curfield == NULL)
fatalerror("INPUT_TOKEN_KEYDELTA encountered with no active field");
TOKEN_UNGET_UINT32(ipt); 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); TOKEN_GET_UINT32_UNPACK2(ipt, entrytype, 8, curfield->delta, -24);
curfield->centerdelta = curfield->delta; curfield->centerdelta = curfield->delta;
break; break;
/* analog autocenter delta */ /* analog autocenter delta */
case INPUT_TOKEN_CENTERDELTA: case INPUT_TOKEN_CENTERDELTA:
if (curfield == NULL)
fatalerror("INPUT_TOKEN_CENTERDELTA encountered with no active field");
TOKEN_UNGET_UINT32(ipt); 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); TOKEN_GET_UINT32_UNPACK2(ipt, entrytype, 8, curfield->centerdelta, -24);
break; break;
/* analog reverse flags */ /* analog reverse flags */
case INPUT_TOKEN_REVERSE: case INPUT_TOKEN_REVERSE:
if (curfield == NULL) 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; curfield->flags |= ANALOG_FLAG_REVERSE;
break; break;
case INPUT_TOKEN_RESET: case INPUT_TOKEN_RESET:
if (curfield == NULL) 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; curfield->flags |= ANALOG_FLAG_RESET;
break; break;
case INPUT_TOKEN_WRAPS: case INPUT_TOKEN_WRAPS:
if (curfield == NULL) 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; curfield->flags |= ANALOG_FLAG_WRAPS;
break; break;
case INPUT_TOKEN_INVERT: case INPUT_TOKEN_INVERT:
if (curfield == NULL) 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; curfield->flags |= ANALOG_FLAG_INVERT;
break; break;
/* analog crosshair parameters */ /* analog crosshair parameters */
case INPUT_TOKEN_CROSSHAIR: case INPUT_TOKEN_CROSSHAIR:
if (curfield == NULL)
fatalerror("INPUT_TOKEN_CROSSHAIR encountered with no active field");
TOKEN_UNGET_UINT32(ipt); 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_UINT32_UNPACK3(ipt, entrytype, 8, curfield->crossaxis, 4, curfield->crossaltaxis, -20);
TOKEN_GET_UINT64_UNPACK2(ipt, curfield->crossscale, -32, curfield->crossoffset, -32); TOKEN_GET_UINT64_UNPACK2(ipt, curfield->crossscale, -32, curfield->crossoffset, -32);
curfield->crossaltaxis *= 1.0f / 65536.0f; curfield->crossaltaxis *= 1.0f / 65536.0f;
curfield->crossscale *= 1.0f / 65536.0f; curfield->crossscale *= 1.0f / 65536.0f;
curfield->crossoffset *= 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 */ /* analog decrement sequence */
case INPUT_TOKEN_CODE_DEC: 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); 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); TOKEN_GET_UINT64_UNPACK2(ipt, entrytype, 8, val, 32);
input_seq_append_or(&curfield->seq[SEQ_TYPE_DECREMENT], val); input_seq_append_or(&curfield->seq[SEQ_TYPE_DECREMENT], val);
break; break;
/* analog increment sequence */ /* analog increment sequence */
case INPUT_TOKEN_CODE_INC: 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); 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); TOKEN_GET_UINT64_UNPACK2(ipt, entrytype, 8, val, 32);
input_seq_append_or(&curfield->seq[SEQ_TYPE_INCREMENT], val); input_seq_append_or(&curfield->seq[SEQ_TYPE_INCREMENT], val);
break; break;
/* analog wraps flag */ /* analog wraps flag */
case INPUT_TOKEN_FULL_TURN_COUNT: case INPUT_TOKEN_FULL_TURN_COUNT:
if (curfield == NULL)
fatalerror("INPUT_TOKEN_FULL_TURN_COUNT encountered with no active field");
TOKEN_UNGET_UINT32(ipt); 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); TOKEN_GET_UINT32_UNPACK2(ipt, entrytype, 8, curfield->full_turn_count, 24);
break; break;
case INPUT_TOKEN_POSITIONS: case INPUT_TOKEN_POSITIONS:
if (curfield == NULL)
fatalerror("INPUT_TOKEN_POSITIONS encountered with no active field");
TOKEN_UNGET_UINT32(ipt); 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); TOKEN_GET_UINT32_UNPACK2(ipt, entrytype, 8, curfield->max, 24);
break; break;
case INPUT_TOKEN_REMAP_TABLE: case INPUT_TOKEN_REMAP_TABLE:
if (curfield == NULL) 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); curfield->remap_table = TOKEN_GET_PTR(ipt, ui32ptr);
break; break;
/* DIP switch definition */ /* DIP switch definition */
case INPUT_TOKEN_DIPNAME: case INPUT_TOKEN_DIPNAME:
if (curport == NULL) 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); TOKEN_GET_UINT64_UNPACK2(ipt, mask, 32, defval, 32);
curfield = field_config_alloc(curport, IPT_DIPSWITCH, defval, mask); curfield = field_config_alloc(curport, IPT_DIPSWITCH, defval, mask);
cursetting = NULL; cursetting = NULL;
curfield->name = input_port_string_from_token(*ipt++); curfield->name = input_port_string_from_token(*ipt++);
break; break;
/* DIP switch setting */ /* DIP switch setting */
case INPUT_TOKEN_DIPSETTING: case INPUT_TOKEN_DIPSETTING:
if (curfield == NULL)
fatalerror("INPUT_TOKEN_DIPSETTING encountered with no active field");
TOKEN_UNGET_UINT32(ipt); 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); TOKEN_GET_UINT64_UNPACK2(ipt, entrytype, 8, defval, 32);
cursetting = setting_config_alloc(curfield, defval & curfield->mask, input_port_string_from_token(*ipt++)); cursetting = setting_config_alloc(curfield, defval & curfield->mask, input_port_string_from_token(*ipt++));
break; break;
/* special DIP switch with on/off values */ /* special DIP switch with on/off values */
case INPUT_TOKEN_SPECIAL_ONOFF: case INPUT_TOKEN_SPECIAL_ONOFF:
if (curport == NULL)
fatalerror("INPUT_TOKEN_SPECIAL_ONOFF encountered with no active port");
TOKEN_UNGET_UINT32(ipt); TOKEN_UNGET_UINT32(ipt);
TOKEN_GET_UINT32_UNPACK3(ipt, entrytype, 8, hasdiploc, 1, temptoken.i, 23); TOKEN_GET_UINT32_UNPACK3(ipt, entrytype, 8, hasdiploc, 1, temptoken.i, 23);
TOKEN_GET_UINT64_UNPACK2(ipt, mask, 32, defval, 32); 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); curfield = field_config_alloc(curport, IPT_DIPSWITCH, defval, mask);
cursetting = NULL; 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; curfield->seq[SEQ_TYPE_STANDARD].code[0] = KEYCODE_F2;
} }
if (hasdiploc) 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; temptoken.i = INPUT_STRING_Off;
cursetting = setting_config_alloc(curfield, defval & mask, input_port_string_from_token(temptoken)); 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 */ /* configuration definition */
case INPUT_TOKEN_CONFNAME: case INPUT_TOKEN_CONFNAME:
if (curport == NULL) 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); TOKEN_GET_UINT64_UNPACK2(ipt, mask, 32, defval, 32);
curfield = field_config_alloc(curport, IPT_CONFIG, defval, mask); curfield = field_config_alloc(curport, IPT_CONFIG, defval, mask);
cursetting = NULL; cursetting = NULL;
curfield->name = input_port_string_from_token(*ipt++); curfield->name = input_port_string_from_token(*ipt++);
break; break;
/* configuration setting */ /* configuration setting */
case INPUT_TOKEN_CONFSETTING: case INPUT_TOKEN_CONFSETTING:
if (curfield == NULL)
fatalerror("INPUT_TOKEN_CONFSETTING encountered with no active field");
TOKEN_UNGET_UINT32(ipt); 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); TOKEN_GET_UINT64_UNPACK2(ipt, entrytype, 8, defval, 32);
cursetting = setting_config_alloc(curfield, defval & curfield->mask, input_port_string_from_token(*ipt++)); cursetting = setting_config_alloc(curfield, defval & curfield->mask, input_port_string_from_token(*ipt++));
break; break;
/* configuration definition */ /* configuration definition */
case INPUT_TOKEN_CATEGORY_NAME: case INPUT_TOKEN_CATEGORY_NAME:
if (curport == NULL) 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); TOKEN_GET_UINT64_UNPACK2(ipt, mask, 32, defval, 32);
curfield = field_config_alloc(curport, IPT_CATEGORY, defval, mask); curfield = field_config_alloc(curport, IPT_CATEGORY, defval, mask);
cursetting = NULL; cursetting = NULL;
curfield->name = input_port_string_from_token(*ipt++); curfield->name = input_port_string_from_token(*ipt++);
break; break;
/* configuration setting */ /* configuration setting */
case INPUT_TOKEN_CATEGORY_SETTING: case INPUT_TOKEN_CATEGORY_SETTING:
if (curfield == NULL)
fatalerror("INPUT_TOKEN_CATEGORY_SETTING encountered with no active field");
TOKEN_UNGET_UINT32(ipt); 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); TOKEN_GET_UINT64_UNPACK2(ipt, entrytype, 8, defval, 32);
cursetting = setting_config_alloc(curfield, defval & curfield->mask, input_port_string_from_token(*ipt++)); cursetting = setting_config_alloc(curfield, defval & curfield->mask, input_port_string_from_token(*ipt++));
break; break;
/* analog adjuster definition */ /* analog adjuster definition */
case INPUT_TOKEN_ADJUSTER: case INPUT_TOKEN_ADJUSTER:
if (curport == NULL)
fatalerror("INPUT_TOKEN_ADJUSTER encountered with no active port");
TOKEN_UNGET_UINT32(ipt); 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); TOKEN_GET_UINT64_UNPACK2(ipt, entrytype, 8, defval, 32);
curfield = field_config_alloc(curport, IPT_ADJUSTER, defval, 0xff); curfield = field_config_alloc(curport, IPT_ADJUSTER, defval, 0xff);
cursetting = NULL; cursetting = NULL;
curfield->name = TOKEN_GET_STRING(ipt); curfield->name = TOKEN_GET_STRING(ipt);
break; break;
default: default:
fatalerror("Invalid token %d in input ports\n", entrytype); error_buf_append(errorbuf, errorbuflen, "Invalid token %d in input ports\n", entrytype);
break; break;
} }
} }
@ -2949,7 +3101,7 @@ static void setting_config_free(input_setting_config **settingptr)
descriptions 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 *head = NULL;
input_field_diplocation **tailptr = &head; input_field_diplocation **tailptr = &head;
@ -3001,7 +3153,10 @@ static const input_field_diplocation *diplocation_list_alloc(const input_field_c
{ {
char *namecopy; char *namecopy;
if (lastname == NULL) 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); (*tailptr)->swname = namecopy = malloc_or_die(strlen(lastname) + 1);
strcpy(namecopy, lastname); strcpy(namecopy, lastname);
} }
@ -3016,8 +3171,9 @@ static const input_field_diplocation *diplocation_list_alloc(const input_field_c
/* now scan the switch number */ /* now scan the switch number */
if (sscanf(number, "%d", &val) != 1) if (sscanf(number, "%d", &val) != 1)
fatalerror("Switch location '%s' has invalid format!", location); error_buf_append(errorbuf, errorbuflen, "Switch location '%s' has invalid format!\n", location);
(*tailptr)->swnum = val; else
(*tailptr)->swnum = val;
/* advance to the next item */ /* advance to the next item */
curentry = comma; 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++) for (bits = 0, temp = field->mask; temp != 0 && bits < 32; bits++)
temp &= temp - 1; temp &= temp - 1;
if (bits != entries) 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; return head;
} }

View File

@ -936,7 +936,7 @@ time_t input_port_init(running_machine *machine, const input_port_token *tokens)
/* ----- port configurations ----- */ /* ----- port configurations ----- */
/* allocate a list of input ports from the given token list */ /* 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 */ /* free memory allocated from input_port_alloc */
void input_port_config_free(const input_port_config *portlist); void input_port_config_free(const input_port_config *portlist);

View File

@ -128,6 +128,12 @@
#define TOKEN_UNGET_UINT32(tp) ((tp)--) #define TOKEN_UNGET_UINT32(tp) ((tp)--)
#define TOKEN_UNGET_UINT64(tp) ((tp) -= 8 / sizeof(FPTR)) #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 */ /* 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 { \ #define UNSHIFT_AND_MASK32(src, val, bits, shift) do { \
if ((bits) < 0) \ if ((bits) < 0) \

View File

@ -1190,6 +1190,7 @@ static int validate_inputs(int drivnum, const machine_config *config)
const input_field_config *field; const input_field_config *field;
const game_driver *driver = drivers[drivnum]; const game_driver *driver = drivers[drivnum];
int empty_string_found = FALSE; int empty_string_found = FALSE;
char errorbuf[1024];
quark_entry *entry; quark_entry *entry;
int error = FALSE; int error = FALSE;
UINT32 crc; UINT32 crc;
@ -1208,7 +1209,9 @@ static int validate_inputs(int drivnum, const machine_config *config)
quark_add(inputs_table, drivnum, crc); quark_add(inputs_table, drivnum, crc);
/* allocate the input ports */ /* 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 */ /* check for duplicate tags */
for (port = portlist; port != NULL; port = port->next) for (port = portlist; port != NULL; port = port->next)