Handle end of line as a syntactic element in the spec file parser;

backslashes can be used to continue lines. This allows us to skip over
errors to continue parsing, and also to make specification of an entry
point link name optional.
This commit is contained in:
Alexandre Julliard 2003-03-18 05:30:54 +00:00
parent ce61349334
commit 49edd19650
8 changed files with 335 additions and 125 deletions

View File

@ -136,6 +136,7 @@ extern char *xstrdup( const char *str );
extern char *strupper(char *s); extern char *strupper(char *s);
extern void fatal_error( const char *msg, ... ); extern void fatal_error( const char *msg, ... );
extern void fatal_perror( const char *msg, ... ); extern void fatal_perror( const char *msg, ... );
extern void error( const char *msg, ... );
extern void warning( const char *msg, ... ); extern void warning( const char *msg, ... );
extern void output_standard_file_header( FILE *outfile ); extern void output_standard_file_header( FILE *outfile );
extern FILE *open_input_file( const char *srcdir, const char *name ); extern FILE *open_input_file( const char *srcdir, const char *name );
@ -156,7 +157,7 @@ extern void load_res16_file( const char *name );
extern int output_res16_data( FILE *outfile ); extern int output_res16_data( FILE *outfile );
extern int output_res16_directory( unsigned char *buffer ); extern int output_res16_directory( unsigned char *buffer );
extern void output_dll_init( FILE *outfile, const char *constructor, const char *destructor ); extern void output_dll_init( FILE *outfile, const char *constructor, const char *destructor );
extern void parse_debug_channels( const char *srcdir, const char *filename ); extern int parse_debug_channels( const char *srcdir, const char *filename );
extern void BuildGlue( FILE *outfile, const char *srcdir, char **argv ); extern void BuildGlue( FILE *outfile, const char *srcdir, char **argv );
extern void BuildRelays16( FILE *outfile ); extern void BuildRelays16( FILE *outfile );
@ -165,7 +166,7 @@ extern void BuildSpec16File( FILE *outfile );
extern void BuildSpec32File( FILE *outfile ); extern void BuildSpec32File( FILE *outfile );
extern void BuildDef32File( FILE *outfile ); extern void BuildDef32File( FILE *outfile );
extern void BuildDebugFile( FILE *outfile, const char *srcdir, char **argv ); extern void BuildDebugFile( FILE *outfile, const char *srcdir, char **argv );
extern void ParseTopLevel( FILE *file ); extern int ParseTopLevel( FILE *file );
/* global variables */ /* global variables */
@ -180,6 +181,7 @@ extern int debugging;
extern int stack_size; extern int stack_size;
extern int nb_debug_channels; extern int nb_debug_channels;
extern int nb_lib_paths; extern int nb_lib_paths;
extern int nb_errors;
extern int display_warnings; extern int display_warnings;
extern int kill_at; extern int kill_at;

View File

@ -281,10 +281,18 @@ static int read_import_lib( const char *name, struct import *imp )
if (!strcmp( name, "LIBRARY" )) if (!strcmp( name, "LIBRARY" ))
{ {
if (!p) fatal_error( "Expected name after LIBRARY\n" ); if (!p)
{
error( "Expected name after LIBRARY\n" );
goto next;
}
name = p; name = p;
p = next_token( name ); p = next_token( name );
if (p) fatal_error( "Garbage after LIBRARY statement\n" ); if (p)
{
error( "Garbage after LIBRARY statement\n" );
goto next;
}
if (is_already_imported( name )) if (is_already_imported( name ))
{ {
close_input_file( f ); close_input_file( f );
@ -297,11 +305,22 @@ static int read_import_lib( const char *name, struct import *imp )
if (!strcmp( name, "EXPORTS" )) goto next; if (!strcmp( name, "EXPORTS" )) goto next;
/* check for ordinal */ /* check for ordinal */
if (!p) fatal_error( "Expected ordinal after function name\n" ); if (!p)
{
error( "Expected ordinal after function name\n" );
goto next;
}
if (*p != '@' || !isdigit(p[1])) if (*p != '@' || !isdigit(p[1]))
fatal_error( "Expected ordinal after function name '%s'\n", name ); {
error( "Expected ordinal after function name '%s'\n", name );
goto next;
}
ordinal = strtol( p+1, &p, 10 ); ordinal = strtol( p+1, &p, 10 );
if (ordinal >= MAX_ORDINALS) fatal_error( "Invalid ordinal number %d\n", ordinal ); if (ordinal >= MAX_ORDINALS)
{
error( "Invalid ordinal number %d\n", ordinal );
goto next;
}
/* check for optional flags */ /* check for optional flags */
while (p && (p = skip_whitespace(p))) while (p && (p = skip_whitespace(p)))
@ -311,14 +330,22 @@ static int read_import_lib( const char *name, struct import *imp )
if (!strcmp( flags, "NONAME" )) if (!strcmp( flags, "NONAME" ))
{ {
ord_only = 1; ord_only = 1;
if (!ordinal) fatal_error( "Invalid ordinal number %d\n", ordinal ); if (!ordinal)
{
error( "Invalid ordinal number %d\n", ordinal );
goto next;
}
} }
else if (!strcmp( flags, "CONSTANT" ) || !strcmp( flags, "DATA" )) else if (!strcmp( flags, "CONSTANT" ) || !strcmp( flags, "DATA" ))
{ {
/* we don't support importing non-function entry points */ /* we don't support importing non-function entry points */
goto next; goto next;
} }
else fatal_error( "Garbage after ordinal declaration\n" ); else
{
error( "Garbage after ordinal declaration\n" );
goto next;
}
} }
if (imp->nb_exports == size) if (imp->nb_exports == size)
@ -338,7 +365,7 @@ static int read_import_lib( const char *name, struct import *imp )
close_input_file( f ); close_input_file( f );
if (imp->nb_exports) if (imp->nb_exports)
qsort( imp->exports, imp->nb_exports, sizeof(*imp->exports), func_cmp ); qsort( imp->exports, imp->nb_exports, sizeof(*imp->exports), func_cmp );
return 1; return !nb_errors;
} }
/* add a dll to the list of imports */ /* add a dll to the list of imports */
@ -371,7 +398,11 @@ void add_import_dll( const char *name, int delay )
dll_imports = xrealloc( dll_imports, (nb_imports+1) * sizeof(*dll_imports) ); dll_imports = xrealloc( dll_imports, (nb_imports+1) * sizeof(*dll_imports) );
dll_imports[nb_imports++] = imp; dll_imports[nb_imports++] = imp;
} }
else free_imports( imp ); else
{
free_imports( imp );
if (nb_errors) exit(1);
}
} }
/* remove an imported dll, based on its index in the dll_imports array */ /* remove an imported dll, based on its index in the dll_imports array */

View File

@ -49,6 +49,7 @@ int nb_entry_points = 0;
int nb_names = 0; int nb_names = 0;
int nb_debug_channels = 0; int nb_debug_channels = 0;
int nb_lib_paths = 0; int nb_lib_paths = 0;
int nb_errors = 0;
int display_warnings = 0; int display_warnings = 0;
int kill_at = 0; int kill_at = 0;
@ -467,7 +468,7 @@ int main(int argc, char **argv)
{ {
case MODE_SPEC: case MODE_SPEC:
load_resources( argv + 1 ); load_resources( argv + 1 );
ParseTopLevel( input_file ); if (!ParseTopLevel( input_file )) break;
switch (SpecType) switch (SpecType)
{ {
case SPEC_WIN16: case SPEC_WIN16:
@ -491,7 +492,7 @@ int main(int argc, char **argv)
case MODE_DEF: case MODE_DEF:
if (argv[1]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[1] ); if (argv[1]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[1] );
if (SpecType == SPEC_WIN16) fatal_error( "Cannot yet build .def file for 16-bit dlls\n" ); if (SpecType == SPEC_WIN16) fatal_error( "Cannot yet build .def file for 16-bit dlls\n" );
ParseTopLevel( input_file ); if (!ParseTopLevel( input_file )) break;
BuildDef32File( output_file ); BuildDef32File( output_file );
break; break;
case MODE_DEBUG: case MODE_DEBUG:
@ -512,6 +513,7 @@ int main(int argc, char **argv)
do_usage(); do_usage();
break; break;
} }
if (nb_errors) exit(1);
if (output_file_name) if (output_file_name)
{ {
fclose( output_file ); fclose( output_file );

View File

@ -76,17 +76,41 @@ inline static int is_token_separator( char ch )
return (ch == '(' || ch == ')' || ch == '-'); return (ch == '(' || ch == ')' || ch == '-');
} }
static const char * GetTokenInLine(void) /* get the next line from the input file, or return 0 if at eof */
static int get_next_line(void)
{
ParseNext = ParseBuffer;
current_line++;
return (fgets(ParseBuffer, sizeof(ParseBuffer), input_file) != NULL);
}
static const char * GetToken( int allow_eol )
{ {
char *p = ParseNext; char *p = ParseNext;
char *token = TokenBuffer; char *token = TokenBuffer;
/* for (;;)
* Remove initial white space. {
*/ /* remove initial white space */
while (isspace(*p)) p++; p = ParseNext;
while (isspace(*p)) p++;
if ((*p == '\0') || (*p == '#')) return NULL; if (*p == '\\' && p[1] == '\n') /* line continuation */
{
if (!get_next_line())
{
if (!allow_eol) error( "Unexpected end of file\n" );
return NULL;
}
}
else break;
}
if ((*p == '\0') || (*p == '#'))
{
if (!allow_eol) error( "Declaration not terminated properly\n" );
return NULL;
}
/* /*
* Find end of token. * Find end of token.
@ -106,30 +130,13 @@ static const char * GetTokenInLine(void)
return TokenBuffer; return TokenBuffer;
} }
static const char * GetToken( int allow_eof )
{
const char *token;
while ((token = GetTokenInLine()) == NULL)
{
ParseNext = ParseBuffer;
current_line++;
if (fgets(ParseBuffer, sizeof(ParseBuffer), input_file) == NULL)
{
if (!allow_eof) fatal_error( "Unexpected end of file\n" );
return NULL;
}
}
return token;
}
/******************************************************************* /*******************************************************************
* ParseVariable * ParseVariable
* *
* Parse a variable definition. * Parse a variable definition.
*/ */
static void ParseVariable( ORDDEF *odp ) static int ParseVariable( ORDDEF *odp )
{ {
char *endptr; char *endptr;
int *value_array; int *value_array;
@ -138,10 +145,17 @@ static void ParseVariable( ORDDEF *odp )
const char *token; const char *token;
if (SpecType == SPEC_WIN32) if (SpecType == SPEC_WIN32)
fatal_error( "'variable' not supported in Win32, use 'extern' instead\n" ); {
error( "'variable' not supported in Win32, use 'extern' instead\n" );
return 0;
}
token = GetToken(0); if (!(token = GetToken(0))) return 0;
if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token ); if (*token != '(')
{
error( "Expected '(' got '%s'\n", token );
return 0;
}
n_values = 0; n_values = 0;
value_array_size = 25; value_array_size = 25;
@ -149,7 +163,11 @@ static void ParseVariable( ORDDEF *odp )
for (;;) for (;;)
{ {
token = GetToken(0); if (!(token = GetToken(0)))
{
free( value_array );
return 0;
}
if (*token == ')') if (*token == ')')
break; break;
@ -162,11 +180,16 @@ static void ParseVariable( ORDDEF *odp )
} }
if (endptr == NULL || *endptr != '\0') if (endptr == NULL || *endptr != '\0')
fatal_error( "Expected number value, got '%s'\n", token ); {
error( "Expected number value, got '%s'\n", token );
free( value_array );
return 0;
}
} }
odp->u.var.n_values = n_values; odp->u.var.n_values = n_values;
odp->u.var.values = xrealloc(value_array, sizeof(*value_array) * n_values); odp->u.var.values = xrealloc(value_array, sizeof(*value_array) * n_values);
return 1;
} }
@ -175,7 +198,7 @@ static void ParseVariable( ORDDEF *odp )
* *
* Parse a function definition. * Parse a function definition.
*/ */
static void ParseExportFunction( ORDDEF *odp ) static int ParseExportFunction( ORDDEF *odp )
{ {
const char *token; const char *token;
unsigned int i; unsigned int i;
@ -184,26 +207,42 @@ static void ParseExportFunction( ORDDEF *odp )
{ {
case SPEC_WIN16: case SPEC_WIN16:
if (odp->type == TYPE_STDCALL) if (odp->type == TYPE_STDCALL)
fatal_error( "'stdcall' not supported for Win16\n" ); {
error( "'stdcall' not supported for Win16\n" );
return 0;
}
if (odp->type == TYPE_VARARGS) if (odp->type == TYPE_VARARGS)
fatal_error( "'varargs' not supported for Win16\n" ); {
error( "'varargs' not supported for Win16\n" );
return 0;
}
break; break;
case SPEC_WIN32: case SPEC_WIN32:
if ((odp->type == TYPE_PASCAL) || (odp->type == TYPE_PASCAL_16)) if ((odp->type == TYPE_PASCAL) || (odp->type == TYPE_PASCAL_16))
fatal_error( "'pascal' not supported for Win32\n" ); {
error( "'pascal' not supported for Win32\n" );
return 0;
}
if (odp->flags & FLAG_INTERRUPT) if (odp->flags & FLAG_INTERRUPT)
fatal_error( "'interrupt' not supported for Win32\n" ); {
error( "'interrupt' not supported for Win32\n" );
return 0;
}
break; break;
default: default:
break; break;
} }
token = GetToken(0); if (!(token = GetToken(0))) return 0;
if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token ); if (*token != '(')
{
error( "Expected '(' got '%s'\n", token );
return 0;
}
for (i = 0; i < sizeof(odp->u.func.arg_types); i++) for (i = 0; i < sizeof(odp->u.func.arg_types); i++)
{ {
token = GetToken(0); if (!(token = GetToken(0))) return 0;
if (*token == ')') if (*token == ')')
break; break;
@ -226,7 +265,11 @@ static void ParseExportFunction( ORDDEF *odp )
odp->u.func.arg_types[i++] = 'l'; odp->u.func.arg_types[i++] = 'l';
if (i < sizeof(odp->u.func.arg_types)) odp->u.func.arg_types[i] = 'l'; if (i < sizeof(odp->u.func.arg_types)) odp->u.func.arg_types[i] = 'l';
} }
else fatal_error( "Unknown variable type '%s'\n", token ); else
{
error( "Unknown argument type '%s'\n", token );
return 0;
}
if (SpecType == SPEC_WIN32) if (SpecType == SPEC_WIN32)
{ {
@ -236,22 +279,44 @@ static void ParseExportFunction( ORDDEF *odp )
strcmp(token, "wstr") && strcmp(token, "wstr") &&
strcmp(token, "double")) strcmp(token, "double"))
{ {
fatal_error( "Type '%s' not supported for Win32\n", token ); error( "Type '%s' not supported for Win32\n", token );
return 0;
} }
} }
} }
if ((*token != ')') || (i >= sizeof(odp->u.func.arg_types))) if ((*token != ')') || (i >= sizeof(odp->u.func.arg_types)))
fatal_error( "Too many arguments\n" ); {
error( "Too many arguments\n" );
return 0;
}
odp->u.func.arg_types[i] = '\0'; odp->u.func.arg_types[i] = '\0';
if (odp->type == TYPE_VARARGS) if (odp->type == TYPE_VARARGS)
odp->flags |= FLAG_NORELAY; /* no relay debug possible for varags entry point */ odp->flags |= FLAG_NORELAY; /* no relay debug possible for varags entry point */
odp->link_name = xstrdup( GetToken(0) );
if (strchr( odp->link_name, '.' )) if (!(token = GetToken(1)))
{ {
if (SpecType == SPEC_WIN16) fatal_error( "Forwarded functions not supported for Win16\n" ); if (!strcmp( odp->name, "@" ))
odp->flags |= FLAG_FORWARD; {
error( "Missing handler name for anonymous function\n" );
return 0;
}
odp->link_name = xstrdup( odp->name );
} }
else
{
odp->link_name = xstrdup( token );
if (strchr( odp->link_name, '.' ))
{
if (SpecType == SPEC_WIN16)
{
error( "Forwarded functions not supported for Win16\n" );
return 0;
}
odp->flags |= FLAG_FORWARD;
}
}
return 1;
} }
@ -260,17 +325,26 @@ static void ParseExportFunction( ORDDEF *odp )
* *
* Parse an 'equate' definition. * Parse an 'equate' definition.
*/ */
static void ParseEquate( ORDDEF *odp ) static int ParseEquate( ORDDEF *odp )
{ {
char *endptr; char *endptr;
int value;
const char *token;
const char *token = GetToken(0);
int value = strtol(token, &endptr, 0);
if (endptr == NULL || *endptr != '\0')
fatal_error( "Expected number value, got '%s'\n", token );
if (SpecType == SPEC_WIN32) if (SpecType == SPEC_WIN32)
fatal_error( "'equate' not supported for Win32\n" ); {
error( "'equate' not supported for Win32\n" );
return 0;
}
if (!(token = GetToken(0))) return 0;
value = strtol(token, &endptr, 0);
if (endptr == NULL || *endptr != '\0')
{
error( "Expected number value, got '%s'\n", token );
return 0;
}
odp->u.abs.value = value; odp->u.abs.value = value;
return 1;
} }
@ -279,10 +353,11 @@ static void ParseEquate( ORDDEF *odp )
* *
* Parse a 'stub' definition. * Parse a 'stub' definition.
*/ */
static void ParseStub( ORDDEF *odp ) static int ParseStub( ORDDEF *odp )
{ {
odp->u.func.arg_types[0] = '\0'; odp->u.func.arg_types[0] = '\0';
odp->link_name = xstrdup(""); odp->link_name = xstrdup("");
return 1;
} }
@ -291,12 +366,30 @@ static void ParseStub( ORDDEF *odp )
* *
* Parse an 'extern' definition. * Parse an 'extern' definition.
*/ */
static void ParseExtern( ORDDEF *odp ) static int ParseExtern( ORDDEF *odp )
{ {
const char *token;
if (SpecType == SPEC_WIN16) if (SpecType == SPEC_WIN16)
fatal_error( "'extern' not supported for Win16, use 'variable' instead\n" ); {
odp->link_name = xstrdup( GetToken(0) ); error( "'extern' not supported for Win16, use 'variable' instead\n" );
if (strchr( odp->link_name, '.' )) odp->flags |= FLAG_FORWARD; return 0;
}
if (!(token = GetToken(1)))
{
if (!strcmp( odp->name, "@" ))
{
error( "Missing handler name for anonymous extern\n" );
return 0;
}
odp->link_name = xstrdup( odp->name );
}
else
{
odp->link_name = xstrdup( token );
if (strchr( odp->link_name, '.' )) odp->flags |= FLAG_FORWARD;
}
return 1;
} }
@ -312,13 +405,17 @@ static const char *ParseFlags( ORDDEF *odp )
do do
{ {
token = GetToken(0); if (!(token = GetToken(0))) break;
for (i = 0; FlagNames[i]; i++) for (i = 0; FlagNames[i]; i++)
if (!strcmp( FlagNames[i], token )) break; if (!strcmp( FlagNames[i], token )) break;
if (!FlagNames[i]) fatal_error( "Unknown flag '%s'\n", token ); if (!FlagNames[i])
{
error( "Unknown flag '%s'\n", token );
return NULL;
}
odp->flags |= 1 << i; odp->flags |= 1 << i;
token = GetToken(0); token = GetToken(0);
} while (*token == '-'); } while (token && *token == '-');
return token; return token;
} }
@ -342,7 +439,7 @@ static void fix_export_name( char *name )
* *
* Parse an ordinal definition. * Parse an ordinal definition.
*/ */
static void ParseOrdinal(int ordinal) static int ParseOrdinal(int ordinal)
{ {
const char *token; const char *token;
@ -350,17 +447,20 @@ static void ParseOrdinal(int ordinal)
memset( odp, 0, sizeof(*odp) ); memset( odp, 0, sizeof(*odp) );
EntryPoints[nb_entry_points++] = odp; EntryPoints[nb_entry_points++] = odp;
token = GetToken(0); if (!(token = GetToken(0))) goto error;
for (odp->type = 0; odp->type < TYPE_NBTYPES; odp->type++) for (odp->type = 0; odp->type < TYPE_NBTYPES; odp->type++)
if (TypeNames[odp->type] && !strcmp( token, TypeNames[odp->type] )) if (TypeNames[odp->type] && !strcmp( token, TypeNames[odp->type] ))
break; break;
if (odp->type >= TYPE_NBTYPES) if (odp->type >= TYPE_NBTYPES)
fatal_error( "Expected type after ordinal, found '%s' instead\n", token ); {
error( "Expected type after ordinal, found '%s' instead\n", token );
goto error;
}
token = GetToken(0); if (!(token = GetToken(0))) goto error;
if (*token == '-') token = ParseFlags( odp ); if (*token == '-' && !(token = ParseFlags( odp ))) goto error;
odp->name = xstrdup( token ); odp->name = xstrdup( token );
fix_export_name( odp->name ); fix_export_name( odp->name );
@ -370,23 +470,23 @@ static void ParseOrdinal(int ordinal)
switch(odp->type) switch(odp->type)
{ {
case TYPE_VARIABLE: case TYPE_VARIABLE:
ParseVariable( odp ); if (!ParseVariable( odp )) goto error;
break; break;
case TYPE_PASCAL_16: case TYPE_PASCAL_16:
case TYPE_PASCAL: case TYPE_PASCAL:
case TYPE_STDCALL: case TYPE_STDCALL:
case TYPE_VARARGS: case TYPE_VARARGS:
case TYPE_CDECL: case TYPE_CDECL:
ParseExportFunction( odp ); if (!ParseExportFunction( odp )) goto error;
break; break;
case TYPE_ABS: case TYPE_ABS:
ParseEquate( odp ); if (!ParseEquate( odp )) goto error;
break; break;
case TYPE_STUB: case TYPE_STUB:
ParseStub( odp ); if (!ParseStub( odp )) goto error;
break; break;
case TYPE_EXTERN: case TYPE_EXTERN:
ParseExtern( odp ); if (!ParseExtern( odp )) goto error;
break; break;
default: default:
assert( 0 ); assert( 0 );
@ -398,14 +498,22 @@ static void ParseOrdinal(int ordinal)
/* ignore this entry point on non-Intel archs */ /* ignore this entry point on non-Intel archs */
EntryPoints[--nb_entry_points] = NULL; EntryPoints[--nb_entry_points] = NULL;
free( odp ); free( odp );
return; return 1;
} }
#endif #endif
if (ordinal != -1) if (ordinal != -1)
{ {
if (!ordinal) fatal_error( "Ordinal 0 is not valid\n" ); if (!ordinal)
if (ordinal >= MAX_ORDINALS) fatal_error( "Ordinal number %d too large\n", ordinal ); {
error( "Ordinal 0 is not valid\n" );
goto error;
}
if (ordinal >= MAX_ORDINALS)
{
error( "Ordinal number %d too large\n", ordinal );
goto error;
}
if (ordinal > Limit) Limit = ordinal; if (ordinal > Limit) Limit = ordinal;
if (ordinal < Base) Base = ordinal; if (ordinal < Base) Base = ordinal;
odp->ordinal = ordinal; odp->ordinal = ordinal;
@ -415,14 +523,27 @@ static void ParseOrdinal(int ordinal)
if (!strcmp( odp->name, "@" ) || odp->flags & FLAG_NONAME) if (!strcmp( odp->name, "@" ) || odp->flags & FLAG_NONAME)
{ {
if (ordinal == -1) if (ordinal == -1)
fatal_error( "Nameless function needs an explicit ordinal number\n" ); {
error( "Nameless function needs an explicit ordinal number\n" );
goto error;
}
if (SpecType != SPEC_WIN32) if (SpecType != SPEC_WIN32)
fatal_error( "Nameless functions not supported for Win16\n" ); {
error( "Nameless functions not supported for Win16\n" );
goto error;
}
if (!strcmp( odp->name, "@" )) free( odp->name ); if (!strcmp( odp->name, "@" )) free( odp->name );
else odp->export_name = odp->name; else odp->export_name = odp->name;
odp->name = NULL; odp->name = NULL;
} }
else Names[nb_names++] = odp; else Names[nb_names++] = odp;
return 1;
error:
EntryPoints[--nb_entry_points] = NULL;
free( odp->name );
free( odp );
return 0;
} }
@ -453,9 +574,9 @@ static void sort_names(void)
if (!strcmp( Names[i]->name, Names[i+1]->name )) if (!strcmp( Names[i]->name, Names[i+1]->name ))
{ {
current_line = max( Names[i]->lineno, Names[i+1]->lineno ); current_line = max( Names[i]->lineno, Names[i+1]->lineno );
fatal_error( "'%s' redefined\n%s:%d: First defined here\n", error( "'%s' redefined\n%s:%d: First defined here\n",
Names[i]->name, input_file_name, Names[i]->name, input_file_name,
min( Names[i]->lineno, Names[i+1]->lineno ) ); min( Names[i]->lineno, Names[i+1]->lineno ) );
} }
} }
} }
@ -466,31 +587,40 @@ static void sort_names(void)
* *
* Parse a spec file. * Parse a spec file.
*/ */
void ParseTopLevel( FILE *file ) int ParseTopLevel( FILE *file )
{ {
const char *token; const char *token;
input_file = file; input_file = file;
current_line = 0; current_line = 0;
while ((token = GetToken(1)) != NULL) while (get_next_line())
{ {
if (!(token = GetToken(1))) continue;
if (strcmp(token, "@") == 0) if (strcmp(token, "@") == 0)
{ {
if (SpecType != SPEC_WIN32) if (SpecType != SPEC_WIN32)
fatal_error( "'@' ordinals not supported for Win16\n" ); {
ParseOrdinal( -1 ); error( "'@' ordinals not supported for Win16\n" );
} continue;
else if (IsNumberString(token)) }
{ if (!ParseOrdinal( -1 )) continue;
ParseOrdinal( atoi(token) ); }
} else if (IsNumberString(token))
else {
fatal_error( "Expected ordinal declaration\n" ); if (!ParseOrdinal( atoi(token) )) continue;
}
else
{
error( "Expected ordinal declaration, got '%s'\n", token );
continue;
}
if ((token = GetToken(1))) error( "Syntax error near '%s'\n", token );
} }
current_line = 0; /* no longer parsing the input file */ current_line = 0; /* no longer parsing the input file */
sort_names(); sort_names();
return !nb_errors;
} }
@ -514,7 +644,7 @@ static void add_debug_channel( const char *name )
* *
* Parse a source file and extract the debug channel definitions. * Parse a source file and extract the debug channel definitions.
*/ */
void parse_debug_channels( const char *srcdir, const char *filename ) int parse_debug_channels( const char *srcdir, const char *filename )
{ {
FILE *file; FILE *file;
int eol_seen = 1; int eol_seen = 1;
@ -540,21 +670,32 @@ void parse_debug_channels( const char *srcdir, const char *filename )
p += 26; p += 26;
while (isspace(*p)) p++; while (isspace(*p)) p++;
if (*p != '(') if (*p != '(')
fatal_error( "invalid debug channel specification '%s'\n", ParseBuffer ); {
error( "invalid debug channel specification '%s'\n", ParseBuffer );
goto next;
}
p++; p++;
while (isspace(*p)) p++; while (isspace(*p)) p++;
if (!isalpha(*p)) if (!isalpha(*p))
fatal_error( "invalid debug channel specification '%s'\n", ParseBuffer ); {
error( "invalid debug channel specification '%s'\n", ParseBuffer );
goto next;
}
channel = p; channel = p;
while (isalnum(*p) || *p == '_') p++; while (isalnum(*p) || *p == '_') p++;
end = p; end = p;
while (isspace(*p)) p++; while (isspace(*p)) p++;
if (*p != ')') if (*p != ')')
fatal_error( "invalid debug channel specification '%s'\n", ParseBuffer ); {
error( "invalid debug channel specification '%s'\n", ParseBuffer );
goto next;
}
*end = 0; *end = 0;
add_debug_channel( channel ); add_debug_channel( channel );
} }
next:
current_line++; current_line++;
} }
close_input_file( file ); close_input_file( file );
return !nb_errors;
} }

View File

@ -451,14 +451,17 @@ static void BuildCallFrom16Func( FILE *outfile, const char *profile, const char
* routines by yourself. * routines by yourself.
* *
*/ */
static void BuildCallTo16Func( FILE *outfile, const char *profile, const char *prefix ) static int BuildCallTo16Func( FILE *outfile, const char *profile, const char *prefix )
{ {
const char *args = profile + 5; const char *args = profile + 5;
int i, argsize = 0, short_ret = 0; int i, argsize = 0, short_ret = 0;
if (!strncmp( "word_", profile, 5 )) short_ret = 1; if (!strncmp( "word_", profile, 5 )) short_ret = 1;
else if (strncmp( "long_", profile, 5 )) else if (strncmp( "long_", profile, 5 ))
fatal_error( "Invalid function name '%s'\n", profile ); {
error( "Invalid function name '%s'\n", profile );
return 0;
}
fprintf( outfile, "unsigned %s __stdcall %s_CallTo16_%s( void (*proc)()", fprintf( outfile, "unsigned %s __stdcall %s_CallTo16_%s( void (*proc)()",
short_ret? "short" : "int", prefix, profile ); short_ret? "short" : "int", prefix, profile );
@ -470,7 +473,9 @@ static void BuildCallTo16Func( FILE *outfile, const char *profile, const char *p
{ {
case 'w': fprintf( outfile, "unsigned short" ); argsize += 2; break; case 'w': fprintf( outfile, "unsigned short" ); argsize += 2; break;
case 'l': fprintf( outfile, "unsigned int" ); argsize += 4; break; case 'l': fprintf( outfile, "unsigned int" ); argsize += 4; break;
default: fatal_error( "Invalid letter '%c' in function name '%s'\n", args[i], profile ); default:
error( "Invalid letter '%c' in function name '%s'\n", args[i], profile );
return 0;
} }
fprintf( outfile, " arg%d", i+1 ); fprintf( outfile, " arg%d", i+1 );
} }
@ -509,6 +514,7 @@ static void BuildCallTo16Func( FILE *outfile, const char *profile, const char *p
#else /* __i386__ */ #else /* __i386__ */
fprintf( outfile, " assert(0);\n}\n\n" ); fprintf( outfile, " assert(0);\n}\n\n" );
#endif /* __i386__ */ #endif /* __i386__ */
return 1;
} }

View File

@ -868,7 +868,10 @@ void BuildDebugFile( FILE *outfile, const char *srcdir, char **argv )
int nr_debug; int nr_debug;
char *prefix, *p; char *prefix, *p;
while (*argv) parse_debug_channels( srcdir, *argv++ ); while (*argv)
{
if (!parse_debug_channels( srcdir, *argv++ )) exit(1);
}
output_standard_file_header( outfile ); output_standard_file_header( outfile );
nr_debug = output_debug( outfile ); nr_debug = output_debug( outfile );

View File

@ -104,6 +104,22 @@ void fatal_perror( const char *msg, ... )
exit(1); exit(1);
} }
void error( const char *msg, ... )
{
va_list valist;
va_start( valist, msg );
if (input_file_name)
{
fprintf( stderr, "%s:", input_file_name );
if (current_line)
fprintf( stderr, "%d:", current_line );
fputc( ' ', stderr );
}
vfprintf( stderr, msg, valist );
va_end( valist );
nb_errors++;
}
void warning( const char *msg, ... ) void warning( const char *msg, ... )
{ {
va_list valist; va_list valist;

View File

@ -191,13 +191,13 @@ A spec file should contain a list of ordinal declarations. The general
syntax is the following: syntax is the following:
.PP .PP
.I ordinal functype .I ordinal functype
.RI [ flags ]\ exportname \ \fB(\fR\ [ args... ] \ \fB)\fI\ handler .RI [ flags ]\ exportname \ \fB(\fR\ [ args... ] \ \fB) \ [ handler ]
.br .br
.IB ordinal\ variable .IB ordinal\ variable
.RI [ flags ]\ exportname \ \fB(\fR\ [ data... ] \ \fB) .RI [ flags ]\ exportname \ \fB(\fR\ [ data... ] \ \fB)
.br .br
.IB ordinal\ extern .IB ordinal\ extern
.RI [ flags ]\ exportname\ symbolname .RI [ flags ]\ exportname \ [ symbolname ]
.br .br
.IB ordinal\ stub .IB ordinal\ stub
.RI [ flags ]\ exportname .RI [ flags ]\ exportname
@ -207,9 +207,11 @@ syntax is the following:
.br .br
.BI #\ comments .BI #\ comments
.PP .PP
Lines whose first character is a Declarations must fit on a single line, except if the end of line is
escaped using a backslash character. The
.B # .B #
will be ignored as comments. character anywhere in a line causes the rest of the line to be ignored
as a comment.
.PP .PP
.I ordinal .I ordinal
specifies the ordinal number corresponding to the entry point, or '@' specifies the ordinal number corresponding to the entry point, or '@'
@ -242,7 +244,7 @@ The function is an interrupt handler routine.
Syntax: Syntax:
.br .br
.I ordinal functype .I ordinal functype
.RI [ flags ]\ exportname \ \fB(\fR\ [ args... ] \ \fB)\fI\ handler .RI [ flags ]\ exportname \ \fB(\fR\ [ args... ] \ \fB) \ [ handler ]
.br .br
This declaration defines a function entry point. The prototype defined by This declaration defines a function entry point. The prototype defined by
@ -312,25 +314,30 @@ is the name of the actual C function that will implement that entry
point in 32-bit mode. The handler can also be specified as point in 32-bit mode. The handler can also be specified as
.IB dllname . function .IB dllname . function
to define a forwarded function (one whose implementation is in another to define a forwarded function (one whose implementation is in another
dll). dll). If
.I handler
is not specified, it is assumed to be identical to
.I exportname.
.PP .PP
This first example defines an entry point for the 16-bit This first example defines an entry point for the 32-bit GetFocus()
CreateWindow() call (the ordinal 100 is just an example):
.IP
100 pascal CreateWindow(ptr ptr long s_word s_word s_word s_word word word word ptr) WIN_CreateWindow
.PP
This second example defines an entry point for the 32-bit GetFocus()
call: call:
.IP .IP
@ stdcall GetFocus() GetFocus @ stdcall GetFocus() GetFocus
.PP .PP
This second example defines an entry point for the 16-bit
CreateWindow() call (the ordinal 100 is just an example); it also
shows how long lines can be split using a backslash:
.IP
100 pascal CreateWindow(ptr ptr long s_word s_word s_word \\
s_word word word word ptr) WIN_CreateWindow
.PP
To declare a function using a variable number of arguments in Win16, To declare a function using a variable number of arguments in Win16,
specify the function as taking no arguments. The arguments are then specify the function as taking no arguments. The arguments are then
available with CURRENT_STACK16->args. In Win32, specify the function available with CURRENT_STACK16->args. In Win32, specify the function
as as
.B varargs .B varargs
and declare it with a '...' parameter in the C file. See the and declare it with a '...' parameter in the C file. See the
wsprintf* functions in user.spec and user32.spec for an example. wsprintf* functions in user.exe.spec and user32.spec for an example.
.SS "Variable ordinals" .SS "Variable ordinals"
Syntax: Syntax:
.br .br
@ -357,7 +364,7 @@ instead (see below).
Syntax: Syntax:
.br .br
.IB ordinal\ extern .IB ordinal\ extern
.RI [ flags ]\ exportname\ symbolname .RI [ flags ]\ exportname \ [ symbolname ]
.PP .PP
This declaration defines an entry that simply maps to a C symbol This declaration defines an entry that simply maps to a C symbol
(variable or function). It only works in Win32 spec files. (variable or function). It only works in Win32 spec files.
@ -368,8 +375,10 @@ that must be defined in the C code. Alternatively, it can be of the
form form
.IB dllname . symbolname .IB dllname . symbolname
to define a forwarded symbol (one whose implementation is in another to define a forwarded symbol (one whose implementation is in another
dll). dll). If
.I symbolname
is not specified, it is assumed to be identical to
.I exportname.
.SS "Stub ordinals" .SS "Stub ordinals"
Syntax: Syntax:
.br .br