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.
oldstable
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 void fatal_error( const char *msg, ... );
extern void fatal_perror( const char *msg, ... );
extern void error( const char *msg, ... );
extern void warning( const char *msg, ... );
extern void output_standard_file_header( FILE *outfile );
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_directory( unsigned char *buffer );
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 BuildRelays16( FILE *outfile );
@ -165,7 +166,7 @@ extern void BuildSpec16File( FILE *outfile );
extern void BuildSpec32File( FILE *outfile );
extern void BuildDef32File( FILE *outfile );
extern void BuildDebugFile( FILE *outfile, const char *srcdir, char **argv );
extern void ParseTopLevel( FILE *file );
extern int ParseTopLevel( FILE *file );
/* global variables */
@ -180,6 +181,7 @@ extern int debugging;
extern int stack_size;
extern int nb_debug_channels;
extern int nb_lib_paths;
extern int nb_errors;
extern int display_warnings;
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 (!p) fatal_error( "Expected name after LIBRARY\n" );
if (!p)
{
error( "Expected name after LIBRARY\n" );
goto next;
}
name = p;
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 ))
{
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;
/* 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]))
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 );
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 */
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" ))
{
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" ))
{
/* we don't support importing non-function entry points */
goto next;
}
else fatal_error( "Garbage after ordinal declaration\n" );
else
{
error( "Garbage after ordinal declaration\n" );
goto next;
}
}
if (imp->nb_exports == size)
@ -338,7 +365,7 @@ static int read_import_lib( const char *name, struct import *imp )
close_input_file( f );
if (imp->nb_exports)
qsort( imp->exports, imp->nb_exports, sizeof(*imp->exports), func_cmp );
return 1;
return !nb_errors;
}
/* 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[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 */

View File

@ -49,6 +49,7 @@ int nb_entry_points = 0;
int nb_names = 0;
int nb_debug_channels = 0;
int nb_lib_paths = 0;
int nb_errors = 0;
int display_warnings = 0;
int kill_at = 0;
@ -467,7 +468,7 @@ int main(int argc, char **argv)
{
case MODE_SPEC:
load_resources( argv + 1 );
ParseTopLevel( input_file );
if (!ParseTopLevel( input_file )) break;
switch (SpecType)
{
case SPEC_WIN16:
@ -491,7 +492,7 @@ int main(int argc, char **argv)
case MODE_DEF:
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" );
ParseTopLevel( input_file );
if (!ParseTopLevel( input_file )) break;
BuildDef32File( output_file );
break;
case MODE_DEBUG:
@ -512,6 +513,7 @@ int main(int argc, char **argv)
do_usage();
break;
}
if (nb_errors) exit(1);
if (output_file_name)
{
fclose( output_file );

View File

@ -76,17 +76,41 @@ inline static int is_token_separator( char 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 *token = TokenBuffer;
/*
* Remove initial white space.
*/
while (isspace(*p)) p++;
for (;;)
{
/* remove initial white space */
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.
@ -106,30 +130,13 @@ static const char * GetTokenInLine(void)
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
*
* Parse a variable definition.
*/
static void ParseVariable( ORDDEF *odp )
static int ParseVariable( ORDDEF *odp )
{
char *endptr;
int *value_array;
@ -138,10 +145,17 @@ static void ParseVariable( ORDDEF *odp )
const char *token;
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 != '(') fatal_error( "Expected '(' got '%s'\n", token );
if (!(token = GetToken(0))) return 0;
if (*token != '(')
{
error( "Expected '(' got '%s'\n", token );
return 0;
}
n_values = 0;
value_array_size = 25;
@ -149,7 +163,11 @@ static void ParseVariable( ORDDEF *odp )
for (;;)
{
token = GetToken(0);
if (!(token = GetToken(0)))
{
free( value_array );
return 0;
}
if (*token == ')')
break;
@ -162,11 +180,16 @@ static void ParseVariable( ORDDEF *odp )
}
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.values = xrealloc(value_array, sizeof(*value_array) * n_values);
return 1;
}
@ -175,7 +198,7 @@ static void ParseVariable( ORDDEF *odp )
*
* Parse a function definition.
*/
static void ParseExportFunction( ORDDEF *odp )
static int ParseExportFunction( ORDDEF *odp )
{
const char *token;
unsigned int i;
@ -184,26 +207,42 @@ static void ParseExportFunction( ORDDEF *odp )
{
case SPEC_WIN16:
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)
fatal_error( "'varargs' not supported for Win16\n" );
{
error( "'varargs' not supported for Win16\n" );
return 0;
}
break;
case SPEC_WIN32:
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)
fatal_error( "'interrupt' not supported for Win32\n" );
{
error( "'interrupt' not supported for Win32\n" );
return 0;
}
break;
default:
break;
}
token = GetToken(0);
if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token );
if (!(token = GetToken(0))) return 0;
if (*token != '(')
{
error( "Expected '(' got '%s'\n", token );
return 0;
}
for (i = 0; i < sizeof(odp->u.func.arg_types); i++)
{
token = GetToken(0);
if (!(token = GetToken(0))) return 0;
if (*token == ')')
break;
@ -226,7 +265,11 @@ static void ParseExportFunction( ORDDEF *odp )
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)
{
@ -236,22 +279,44 @@ static void ParseExportFunction( ORDDEF *odp )
strcmp(token, "wstr") &&
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)))
fatal_error( "Too many arguments\n" );
{
error( "Too many arguments\n" );
return 0;
}
odp->u.func.arg_types[i] = '\0';
if (odp->type == TYPE_VARARGS)
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" );
odp->flags |= FLAG_FORWARD;
if (!strcmp( odp->name, "@" ))
{
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.
*/
static void ParseEquate( ORDDEF *odp )
static int ParseEquate( ORDDEF *odp )
{
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)
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;
return 1;
}
@ -279,10 +353,11 @@ static void ParseEquate( ORDDEF *odp )
*
* Parse a 'stub' definition.
*/
static void ParseStub( ORDDEF *odp )
static int ParseStub( ORDDEF *odp )
{
odp->u.func.arg_types[0] = '\0';
odp->link_name = xstrdup("");
return 1;
}
@ -291,12 +366,30 @@ static void ParseStub( ORDDEF *odp )
*
* Parse an 'extern' definition.
*/
static void ParseExtern( ORDDEF *odp )
static int ParseExtern( ORDDEF *odp )
{
const char *token;
if (SpecType == SPEC_WIN16)
fatal_error( "'extern' not supported for Win16, use 'variable' instead\n" );
odp->link_name = xstrdup( GetToken(0) );
if (strchr( odp->link_name, '.' )) odp->flags |= FLAG_FORWARD;
{
error( "'extern' not supported for Win16, use 'variable' instead\n" );
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
{
token = GetToken(0);
if (!(token = GetToken(0))) break;
for (i = 0; FlagNames[i]; i++)
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;
token = GetToken(0);
} while (*token == '-');
} while (token && *token == '-');
return token;
}
@ -342,7 +439,7 @@ static void fix_export_name( char *name )
*
* Parse an ordinal definition.
*/
static void ParseOrdinal(int ordinal)
static int ParseOrdinal(int ordinal)
{
const char *token;
@ -350,17 +447,20 @@ static void ParseOrdinal(int ordinal)
memset( odp, 0, sizeof(*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++)
if (TypeNames[odp->type] && !strcmp( token, TypeNames[odp->type] ))
break;
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 == '-') token = ParseFlags( odp );
if (!(token = GetToken(0))) goto error;
if (*token == '-' && !(token = ParseFlags( odp ))) goto error;
odp->name = xstrdup( token );
fix_export_name( odp->name );
@ -370,23 +470,23 @@ static void ParseOrdinal(int ordinal)
switch(odp->type)
{
case TYPE_VARIABLE:
ParseVariable( odp );
if (!ParseVariable( odp )) goto error;
break;
case TYPE_PASCAL_16:
case TYPE_PASCAL:
case TYPE_STDCALL:
case TYPE_VARARGS:
case TYPE_CDECL:
ParseExportFunction( odp );
if (!ParseExportFunction( odp )) goto error;
break;
case TYPE_ABS:
ParseEquate( odp );
if (!ParseEquate( odp )) goto error;
break;
case TYPE_STUB:
ParseStub( odp );
if (!ParseStub( odp )) goto error;
break;
case TYPE_EXTERN:
ParseExtern( odp );
if (!ParseExtern( odp )) goto error;
break;
default:
assert( 0 );
@ -398,14 +498,22 @@ static void ParseOrdinal(int ordinal)
/* ignore this entry point on non-Intel archs */
EntryPoints[--nb_entry_points] = NULL;
free( odp );
return;
return 1;
}
#endif
if (ordinal != -1)
{
if (!ordinal) fatal_error( "Ordinal 0 is not valid\n" );
if (ordinal >= MAX_ORDINALS) fatal_error( "Ordinal number %d too large\n", ordinal );
if (!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 < Base) Base = ordinal;
odp->ordinal = ordinal;
@ -415,14 +523,27 @@ static void ParseOrdinal(int ordinal)
if (!strcmp( odp->name, "@" ) || odp->flags & FLAG_NONAME)
{
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)
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 );
else odp->export_name = odp->name;
odp->name = NULL;
}
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 ))
{
current_line = max( Names[i]->lineno, Names[i+1]->lineno );
fatal_error( "'%s' redefined\n%s:%d: First defined here\n",
Names[i]->name, input_file_name,
min( Names[i]->lineno, Names[i+1]->lineno ) );
error( "'%s' redefined\n%s:%d: First defined here\n",
Names[i]->name, input_file_name,
min( Names[i]->lineno, Names[i+1]->lineno ) );
}
}
}
@ -466,31 +587,40 @@ static void sort_names(void)
*
* Parse a spec file.
*/
void ParseTopLevel( FILE *file )
int ParseTopLevel( FILE *file )
{
const char *token;
input_file = file;
current_line = 0;
while ((token = GetToken(1)) != NULL)
while (get_next_line())
{
if (!(token = GetToken(1))) continue;
if (strcmp(token, "@") == 0)
{
{
if (SpecType != SPEC_WIN32)
fatal_error( "'@' ordinals not supported for Win16\n" );
ParseOrdinal( -1 );
}
else if (IsNumberString(token))
{
ParseOrdinal( atoi(token) );
}
else
fatal_error( "Expected ordinal declaration\n" );
{
error( "'@' ordinals not supported for Win16\n" );
continue;
}
if (!ParseOrdinal( -1 )) continue;
}
else if (IsNumberString(token))
{
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 */
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.
*/
void parse_debug_channels( const char *srcdir, const char *filename )
int parse_debug_channels( const char *srcdir, const char *filename )
{
FILE *file;
int eol_seen = 1;
@ -540,21 +670,32 @@ void parse_debug_channels( const char *srcdir, const char *filename )
p += 26;
while (isspace(*p)) p++;
if (*p != '(')
fatal_error( "invalid debug channel specification '%s'\n", ParseBuffer );
{
error( "invalid debug channel specification '%s'\n", ParseBuffer );
goto next;
}
p++;
while (isspace(*p)) 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;
while (isalnum(*p) || *p == '_') p++;
end = p;
while (isspace(*p)) p++;
if (*p != ')')
fatal_error( "invalid debug channel specification '%s'\n", ParseBuffer );
{
error( "invalid debug channel specification '%s'\n", ParseBuffer );
goto next;
}
*end = 0;
add_debug_channel( channel );
}
next:
current_line++;
}
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.
*
*/
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;
int i, argsize = 0, short_ret = 0;
if (!strncmp( "word_", profile, 5 )) short_ret = 1;
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)()",
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 '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 );
}
@ -509,6 +514,7 @@ static void BuildCallTo16Func( FILE *outfile, const char *profile, const char *p
#else /* __i386__ */
fprintf( outfile, " assert(0);\n}\n\n" );
#endif /* __i386__ */
return 1;
}

View File

@ -868,7 +868,10 @@ void BuildDebugFile( FILE *outfile, const char *srcdir, char **argv )
int nr_debug;
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 );
nr_debug = output_debug( outfile );

View File

@ -104,6 +104,22 @@ void fatal_perror( const char *msg, ... )
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, ... )
{
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:
.PP
.I ordinal functype
.RI [ flags ]\ exportname \ \fB(\fR\ [ args... ] \ \fB)\fI\ handler
.RI [ flags ]\ exportname \ \fB(\fR\ [ args... ] \ \fB) \ [ handler ]
.br
.IB ordinal\ variable
.RI [ flags ]\ exportname \ \fB(\fR\ [ data... ] \ \fB)
.br
.IB ordinal\ extern
.RI [ flags ]\ exportname\ symbolname
.RI [ flags ]\ exportname \ [ symbolname ]
.br
.IB ordinal\ stub
.RI [ flags ]\ exportname
@ -207,9 +207,11 @@ syntax is the following:
.br
.BI #\ comments
.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 #
will be ignored as comments.
character anywhere in a line causes the rest of the line to be ignored
as a comment.
.PP
.I ordinal
specifies the ordinal number corresponding to the entry point, or '@'
@ -242,7 +244,7 @@ The function is an interrupt handler routine.
Syntax:
.br
.I ordinal functype
.RI [ flags ]\ exportname \ \fB(\fR\ [ args... ] \ \fB)\fI\ handler
.RI [ flags ]\ exportname \ \fB(\fR\ [ args... ] \ \fB) \ [ handler ]
.br
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
.IB dllname . function
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
This first example defines an entry point for the 16-bit
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()
This first example defines an entry point for the 32-bit GetFocus()
call:
.IP
@ stdcall GetFocus() GetFocus
.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,
specify the function as taking no arguments. The arguments are then
available with CURRENT_STACK16->args. In Win32, specify the function
as
.B varargs
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"
Syntax:
.br
@ -357,7 +364,7 @@ instead (see below).
Syntax:
.br
.IB ordinal\ extern
.RI [ flags ]\ exportname\ symbolname
.RI [ flags ]\ exportname \ [ symbolname ]
.PP
This declaration defines an entry that simply maps to a C symbol
(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
.IB dllname . symbolname
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"
Syntax:
.br