Commit 49edd196 authored by Alexandre Julliard's avatar Alexandre Julliard

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.
parent ce613493
...@@ -136,6 +136,7 @@ extern char *xstrdup( const char *str ); ...@@ -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 ); ...@@ -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 ); ...@@ -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; ...@@ -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;
......
...@@ -281,10 +281,18 @@ static int read_import_lib( const char *name, struct import *imp ) ...@@ -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 ) ...@@ -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 ) ...@@ -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 ) ...@@ -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 ) ...@@ -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 */
......
...@@ -49,6 +49,7 @@ int nb_entry_points = 0; ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 );
......
...@@ -451,14 +451,17 @@ static void BuildCallFrom16Func( FILE *outfile, const char *profile, const char ...@@ -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 ...@@ -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 ...@@ -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;
} }
......
...@@ -868,7 +868,10 @@ void BuildDebugFile( FILE *outfile, const char *srcdir, char **argv ) ...@@ -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 );
......
...@@ -104,6 +104,22 @@ void fatal_perror( const char *msg, ... ) ...@@ -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;
......
...@@ -191,13 +191,13 @@ A spec file should contain a list of ordinal declarations. The general ...@@ -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: ...@@ -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. ...@@ -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 ...@@ -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
.PP .I handler
This first example defines an entry point for the 16-bit is not specified, it is assumed to be identical to
CreateWindow() call (the ordinal 100 is just an example): .I exportname.
.IP
100 pascal CreateWindow(ptr ptr long s_word s_word s_word s_word word word word ptr) WIN_CreateWindow
.PP .PP
This second example defines an entry point for the 32-bit GetFocus() This first 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). ...@@ -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 ...@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment