Sync to Wine-20050211

svn path=/trunk/; revision=13573
This commit is contained in:
Gé van Geldorp 2005-02-14 18:39:15 +00:00
parent eb51ddf583
commit 36e7b406b5
15 changed files with 7863 additions and 0 deletions

View file

@ -0,0 +1,43 @@
#
# winebuild
#
PATH_TO_TOP = ../..
include $(PATH_TO_TOP)/rules.mak
TARGET = winebuild$(EXE_POSTFIX)
all: $(TARGET)
# relay.o spec16.o
OBJECTS = \
import.o \
main.o \
parser.o \
res16.o \
res32.o \
spec32.o \
utils.o \
mkstemps.o
CLEAN_FILES = *.o $(TARGET)
HOST_CFLAGS = -D__USE_W32API -I$(PATH_TO_TOP)/include/wine
%.o: %.c
$(HOST_CC) $(HOST_CFLAGS) -c $< -o $@
$(TARGET): $(OBJECTS)
$(HOST_CC) $(OBJECTS) -o $(TARGET)
ifeq ($(HOST),mingw32-linux)
clean:
rm -f $(CLEAN_FILES)
endif
ifneq ($(HOST),mingw32-linux)
clean:
del $(CLEAN_FILES)
endif
.PHONY: clean

View file

@ -0,0 +1,42 @@
TOPSRCDIR = @top_srcdir@
TOPOBJDIR = ../..
SRCDIR = @srcdir@
VPATH = @srcdir@
EXEEXT = @EXEEXT@
PROGRAMS = winebuild$(EXEEXT)
MODULE = none
C_SRCS = \
import.c \
main.c \
parser.c \
relay.c \
res16.c \
res32.c \
spec16.c \
spec32.c \
utils.c
all: $(PROGRAMS) winebuild.man
@MAKE_RULES@
winebuild$(EXEEXT): $(OBJS)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBPORT) $(LDFLAGS)
winebuild.man: winebuild.man.in
sed -e 's,@PACKAGE_STRING\@,@PACKAGE_STRING@,g' $(SRCDIR)/winebuild.man.in >$@ || ($(RM) $@ && false)
install:: $(PROGRAMS) winebuild.man
$(MKINSTALLDIRS) $(bindir) $(mandir)/man$(prog_manext)
$(INSTALL_PROGRAM) winebuild$(EXEEXT) $(bindir)/winebuild$(EXEEXT)
$(INSTALL_DATA) winebuild.man $(mandir)/man$(prog_manext)/winebuild.$(prog_manext)
uninstall::
$(RM) $(bindir)/winebuild$(EXEEXT) $(mandir)/man$(prog_manext)/winebuild.$(prog_manext)
clean::
$(RM) winebuild.man
### Dependencies:

View file

@ -0,0 +1,213 @@
/*
* Copyright 1993 Robert J. Amstadt
* Copyright 1995 Martin von Loewis
* Copyright 1995, 1996, 1997 Alexandre Julliard
* Copyright 1997 Eric Youngdale
* Copyright 1999 Ulrich Weigand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __WINE_BUILD_H
#define __WINE_BUILD_H
#ifndef __WINE_CONFIG_H
# error You must include config.h to use this header
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef enum
{
TYPE_VARIABLE, /* variable */
TYPE_PASCAL, /* pascal function (Win16) */
TYPE_ABS, /* absolute value (Win16) */
TYPE_STUB, /* unimplemented stub */
TYPE_STDCALL, /* stdcall function (Win32) */
TYPE_CDECL, /* cdecl function (Win32) */
TYPE_VARARGS, /* varargs function (Win32) */
TYPE_EXTERN, /* external symbol (Win32) */
TYPE_NBTYPES
} ORD_TYPE;
typedef enum
{
SPEC_WIN16,
SPEC_WIN32
} SPEC_TYPE;
typedef struct
{
int n_values;
int *values;
} ORD_VARIABLE;
typedef struct
{
char arg_types[21];
} ORD_FUNCTION;
typedef struct
{
int value;
} ORD_ABS;
typedef struct
{
ORD_TYPE type;
int ordinal;
int offset;
int lineno;
int flags;
char *name; /* public name of this function */
char *link_name; /* name of the C symbol to link to */
char *export_name; /* name exported under for noname exports */
union
{
ORD_VARIABLE var;
ORD_FUNCTION func;
ORD_ABS abs;
} u;
} ORDDEF;
typedef struct
{
char *file_name; /* file name of the dll */
char *dll_name; /* internal name of the dll */
char *owner_name; /* name of the 32-bit dll owning this one */
char *init_func; /* initialization routine */
SPEC_TYPE type; /* type of dll (Win16/Win32) */
int base; /* ordinal base */
int limit; /* ordinal limit */
int stack_size; /* exe stack size */
int heap_size; /* exe heap size */
int nb_entry_points; /* number of used entry points */
int alloc_entry_points; /* number of allocated entry points */
int nb_names; /* number of entry points with names */
int nb_resources; /* number of resources */
int characteristics; /* characteristics for the PE header */
int subsystem; /* subsystem id */
int subsystem_major; /* subsystem version major number */
int subsystem_minor; /* subsystem version minor number */
ORDDEF *entry_points; /* dll entry points */
ORDDEF **names; /* array of entry point names (points into entry_points) */
ORDDEF **ordinals; /* array of dll ordinals (points into entry_points) */
struct resource *resources; /* array of dll resources (format differs between Win16/Win32) */
} DLLSPEC;
/* entry point flags */
#define FLAG_NORELAY 0x01 /* don't use relay debugging for this function */
#define FLAG_NONAME 0x02 /* don't import function by name */
#define FLAG_RET16 0x04 /* function returns a 16-bit value */
#define FLAG_RET64 0x08 /* function returns a 64-bit value */
#define FLAG_I386 0x10 /* function is i386 only */
#define FLAG_REGISTER 0x20 /* use register calling convention */
#define FLAG_PRIVATE 0x40 /* function is private (cannot be imported) */
#define FLAG_FORWARD 0x80 /* function is a forwarded name */
/* Offset of a structure field relative to the start of the struct */
#define STRUCTOFFSET(type,field) ((int)&((type *)0)->field)
/* Offset of register relative to the start of the CONTEXT struct */
#define CONTEXTOFFSET(reg) STRUCTOFFSET(CONTEXT86,reg)
/* Offset of register relative to the start of the STACK16FRAME struct */
#define STACK16OFFSET(reg) STRUCTOFFSET(STACK16FRAME,reg)
/* Offset of register relative to the start of the STACK32FRAME struct */
#define STACK32OFFSET(reg) STRUCTOFFSET(STACK32FRAME,reg)
/* Offset of the stack pointer relative to %fs:(0) */
#define STACKOFFSET (STRUCTOFFSET(TEB,cur_stack))
#define MAX_ORDINALS 65535
/* global functions */
#ifndef __GNUC__
#define __attribute__(X)
#endif
extern void *xmalloc (size_t size);
extern void *xrealloc (void *ptr, size_t size);
extern char *xstrdup( const char *str );
extern char *strupper(char *s);
extern void fatal_error( const char *msg, ... )
__attribute__ ((__format__ (__printf__, 1, 2)));
extern void fatal_perror( const char *msg, ... )
__attribute__ ((__format__ (__printf__, 1, 2)));
extern void error( const char *msg, ... )
__attribute__ ((__format__ (__printf__, 1, 2)));
extern void warning( const char *msg, ... )
__attribute__ ((__format__ (__printf__, 1, 2)));
extern void output_standard_file_header( FILE *outfile );
extern FILE *open_input_file( const char *srcdir, const char *name );
extern void close_input_file( FILE *file );
extern void dump_bytes( FILE *outfile, const unsigned char *data, int len,
const char *label, int constant );
extern int remove_stdcall_decoration( char *name );
extern DLLSPEC *alloc_dll_spec(void);
extern void free_dll_spec( DLLSPEC *spec );
extern const char *make_c_identifier( const char *str );
extern int get_alignment(int alignBoundary);
extern void add_import_dll( const char *name, int delay );
extern void add_ignore_symbol( const char *name );
extern void read_undef_symbols( char **argv );
extern int resolve_imports( DLLSPEC *spec );
extern int output_imports( FILE *outfile, DLLSPEC *spec );
extern int load_res32_file( const char *name, DLLSPEC *spec );
extern void output_resources( FILE *outfile, DLLSPEC *spec );
extern void load_res16_file( const char *name, DLLSPEC *spec );
extern int output_res16_data( FILE *outfile, DLLSPEC *spec );
extern int output_res16_directory( unsigned char *buffer, DLLSPEC *spec );
extern void output_dll_init( FILE *outfile, const char *constructor, const char *destructor );
extern void BuildRelays16( FILE *outfile );
extern void BuildRelays32( FILE *outfile );
extern void BuildSpec16File( FILE *outfile, DLLSPEC *spec );
extern void BuildSpec32File( FILE *outfile, DLLSPEC *spec );
extern void BuildDef32File( FILE *outfile, DLLSPEC *spec );
extern void BuildDebugFile( FILE *outfile, const char *srcdir, char **argv );
extern void BuildPedllFile( FILE *outfile, DLLSPEC *spec );
extern int parse_spec_file( FILE *file, DLLSPEC *spec );
extern int parse_def_file( FILE *file, DLLSPEC *spec );
extern int parse_debug_channels( const char *srcdir, const char *filename );
/* global variables */
extern int current_line;
extern int UsePIC;
extern int debugging;
extern int nb_debug_channels;
extern int nb_lib_paths;
extern int nb_errors;
extern int display_warnings;
extern int kill_at;
extern char *input_file_name;
extern const char *output_file_name;
extern char **debug_channels;
extern char **lib_path;
extern char *ld_command;
extern char *nm_command;
#endif /* __WINE_BUILD_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,495 @@
/*
* Main function
*
* Copyright 1993 Robert J. Amstadt
* Copyright 1995 Martin von Loewis
* Copyright 1995, 1996, 1997 Alexandre Julliard
* Copyright 1997 Eric Youngdale
* Copyright 1999 Ulrich Weigand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <assert.h>
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#ifdef HAVE_GETOPT_H
# include <getopt.h>
#endif
#include "winglue.h"
#include "build.h"
int UsePIC = 0;
int nb_debug_channels = 0;
int nb_lib_paths = 0;
int nb_errors = 0;
int display_warnings = 0;
int kill_at = 0;
/* we only support relay debugging on i386 */
#ifdef __i386__
int debugging = 1;
#else
int debugging = 0;
#endif
char **debug_channels = NULL;
char **lib_path = NULL;
char *input_file_name = NULL;
const char *output_file_name = NULL;
char *ld_command = "ld";
char *nm_command = "nm";
static FILE *output_file;
static const char *current_src_dir;
static int nb_res_files;
static char **res_files;
static char *spec_file_name;
/* execution mode */
enum exec_mode_values
{
MODE_NONE,
MODE_DLL,
MODE_EXE,
MODE_DEF,
MODE_DEBUG,
MODE_RELAY16,
MODE_RELAY32,
MODE_PEDLL
};
static enum exec_mode_values exec_mode = MODE_NONE;
/* set the dll file name from the input file name */
static void set_dll_file_name( const char *name, DLLSPEC *spec )
{
char *p;
if (spec->file_name) return;
if ((p = strrchr( name, '\\' ))) name = p + 1;
if ((p = strrchr( name, '/' ))) name = p + 1;
spec->file_name = xmalloc( strlen(name) + 5 );
strcpy( spec->file_name, name );
if ((p = strrchr( spec->file_name, '.' )))
{
if (!strcmp( p, ".spec" ) || !strcmp( p, ".def" )) *p = 0;
}
if (!strchr( spec->file_name, '.' )) strcat( spec->file_name, ".dll" );
}
/* set the dll subsystem */
static void set_subsystem( const char *subsystem, DLLSPEC *spec )
{
char *major, *minor, *str = xstrdup( subsystem );
if ((major = strchr( str, ':' ))) *major++ = 0;
if (!strcmp( str, "native" )) spec->subsystem = IMAGE_SUBSYSTEM_NATIVE;
else if (!strcmp( str, "windows" )) spec->subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI;
else if (!strcmp( str, "console" )) spec->subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
else fatal_error( "Invalid subsystem name '%s'\n", subsystem );
if (major)
{
if ((minor = strchr( major, '.' )))
{
*minor++ = 0;
spec->subsystem_minor = atoi( minor );
}
spec->subsystem_major = atoi( major );
}
free( str );
}
/* cleanup on program exit */
static void cleanup(void)
{
if (output_file_name) unlink( output_file_name );
}
/* clean things up when aborting on a signal */
static void exit_on_signal( int sig )
{
exit(1); /* this will call atexit functions */
}
/*******************************************************************
* command-line option handling
*/
static const char usage_str[] =
"Usage: winebuild [OPTIONS] [FILES]\n\n"
"Options:\n"
" -C --source-dir=DIR Look for source files in DIR\n"
" -d --delay-lib=LIB Import the specified library in delayed mode\n"
" -D SYM Ignored for C flags compatibility\n"
" -e --entry=FUNC Set the DLL entry point function (default: DllMain)\n"
" -f FLAGS Compiler flags (only -fPIC is supported)\n"
" -F --filename=DLLFILE Set the DLL filename (default: from input file name)\n"
" -h --help Display this help message\n"
" -H --heap=SIZE Set the heap size for a Win16 dll\n"
" -i --ignore=SYM[,SYM] Ignore specified symbols when resolving imports\n"
" -I DIR Ignored for C flags compatibility\n"
" -k --kill-at Kill stdcall decorations in generated .def files\n"
" -K FLAGS Compiler flags (only -KPIC is supported)\n"
" --ld-cmd=LD Command to use for linking (default: ld)\n"
" -l --library=LIB Import the specified library\n"
" -L --library-path=DIR Look for imports libraries in DIR\n"
" -M --main-module=MODULE Set the name of the main module for a Win16 dll\n"
" --nm-cmd=NM Command to use to get undefined symbols (default: nm)\n"
" -N --dll-name=DLLNAME Set the DLL name (default: from input file name)\n"
" -o --output=NAME Set the output file name (default: stdout)\n"
" -r --res=RSRC.RES Load resources from RSRC.RES\n"
" --subsystem=SUBSYS Set the subsystem (one of native, windows, console)\n"
" --version Print the version and exit\n"
" -w --warnings Turn on warnings\n"
"\nMode options:\n"
" --dll=FILE Build a .c file from a .spec or .def file\n"
" --def=FILE.SPEC Build a .def file from a spec file\n"
" --exe=NAME Build a .c file for the named executable\n"
" --debug [FILES] Build a .c file with the debug channels declarations\n"
" --relay16 Build the 16-bit relay assembly routines\n"
" --relay32 Build the 32-bit relay assembly routines\n"
" --pedll Build a .c file for PE dll\n\n"
"The mode options are mutually exclusive; you must specify one and only one.\n\n";
enum long_options_values
{
LONG_OPT_DLL = 1,
LONG_OPT_DEF,
LONG_OPT_EXE,
LONG_OPT_DEBUG,
LONG_OPT_LDCMD,
LONG_OPT_NMCMD,
LONG_OPT_RELAY16,
LONG_OPT_RELAY32,
LONG_OPT_SUBSYSTEM,
LONG_OPT_VERSION,
LONG_OPT_PEDLL
};
static const char short_options[] = "C:D:F:H:I:K:L:M:N:d:e:f:hi:kl:m:o:r:w";
static const struct option long_options[] =
{
{ "dll", 1, 0, LONG_OPT_DLL },
{ "def", 1, 0, LONG_OPT_DEF },
{ "exe", 1, 0, LONG_OPT_EXE },
{ "debug", 0, 0, LONG_OPT_DEBUG },
{ "ld-cmd", 1, 0, LONG_OPT_LDCMD },
{ "nm-cmd", 1, 0, LONG_OPT_NMCMD },
{ "relay16", 0, 0, LONG_OPT_RELAY16 },
{ "relay32", 0, 0, LONG_OPT_RELAY32 },
{ "subsystem",1, 0, LONG_OPT_SUBSYSTEM },
{ "version", 0, 0, LONG_OPT_VERSION },
{ "pedll", 1, 0, LONG_OPT_PEDLL },
/* aliases for short options */
{ "source-dir", 1, 0, 'C' },
{ "delay-lib", 1, 0, 'd' },
{ "entry", 1, 0, 'e' },
{ "filename", 1, 0, 'F' },
{ "help", 0, 0, 'h' },
{ "heap", 1, 0, 'H' },
{ "ignore", 1, 0, 'i' },
{ "kill-at", 0, 0, 'k' },
{ "library", 1, 0, 'l' },
{ "library-path", 1, 0, 'L' },
{ "main-module", 1, 0, 'M' },
{ "dll-name", 1, 0, 'N' },
{ "output", 1, 0, 'o' },
{ "res", 1, 0, 'r' },
{ "warnings", 0, 0, 'w' },
{ NULL, 0, 0, 0 }
};
static void usage( int exit_code )
{
fprintf( stderr, "%s", usage_str );
exit( exit_code );
}
static void set_exec_mode( enum exec_mode_values mode )
{
if (exec_mode != MODE_NONE) usage(1);
exec_mode = mode;
}
/* parse options from the argv array and remove all the recognized ones */
static char **parse_options( int argc, char **argv, DLLSPEC *spec )
{
char *p;
int optc;
while ((optc = getopt_long( argc, argv, short_options, long_options, NULL )) != -1)
{
switch(optc)
{
case 'C':
current_src_dir = optarg;
break;
case 'D':
/* ignored */
break;
case 'F':
spec->file_name = xstrdup( optarg );
break;
case 'H':
if (!isdigit(optarg[0]))
fatal_error( "Expected number argument with -H option instead of '%s'\n", optarg );
spec->heap_size = atoi(optarg);
if (spec->heap_size > 65535)
fatal_error( "Invalid heap size %d, maximum is 65535\n", spec->heap_size );
break;
case 'I':
/* ignored */
break;
case 'K':
/* ignored, because cc generates correct code. */
break;
case 'L':
lib_path = xrealloc( lib_path, (nb_lib_paths+1) * sizeof(*lib_path) );
lib_path[nb_lib_paths++] = xstrdup( optarg );
break;
case 'M':
spec->owner_name = xstrdup( optarg );
spec->type = SPEC_WIN16;
break;
case 'N':
spec->dll_name = xstrdup( optarg );
break;
case 'd':
add_import_dll( optarg, 1 );
break;
case 'e':
spec->init_func = xstrdup( optarg );
if ((p = strchr( spec->init_func, '@' ))) *p = 0; /* kill stdcall decoration */
break;
case 'f':
if (!strcmp( optarg, "PIC") || !strcmp( optarg, "pic")) UsePIC = 1;
/* ignore all other flags */
break;
case 'h':
usage(0);
break;
case 'i':
{
char *str = xstrdup( optarg );
char *token = strtok( str, "," );
while (token)
{
add_ignore_symbol( token );
token = strtok( NULL, "," );
}
free( str );
}
break;
case 'k':
kill_at = 1;
break;
case 'l':
add_import_dll( optarg, 0 );
break;
case 'o':
if (unlink( optarg ) == -1 && errno != ENOENT)
fatal_error( "Unable to create output file '%s'\n", optarg );
if (!(output_file = fopen( optarg, "w" )))
fatal_error( "Unable to create output file '%s'\n", optarg );
output_file_name = xstrdup(optarg);
atexit( cleanup ); /* make sure we remove the output file on exit */
break;
case 'r':
res_files = xrealloc( res_files, (nb_res_files+1) * sizeof(*res_files) );
res_files[nb_res_files++] = xstrdup( optarg );
break;
case 'w':
display_warnings = 1;
break;
case LONG_OPT_DLL:
set_exec_mode( MODE_DLL );
spec_file_name = xstrdup( optarg );
set_dll_file_name( optarg, spec );
break;
case LONG_OPT_DEF:
set_exec_mode( MODE_DEF );
spec_file_name = xstrdup( optarg );
set_dll_file_name( optarg, spec );
break;
case LONG_OPT_EXE:
set_exec_mode( MODE_EXE );
if ((p = strrchr( optarg, '/' ))) p++;
else p = optarg;
spec->file_name = xmalloc( strlen(p) + 5 );
strcpy( spec->file_name, p );
if (!strchr( spec->file_name, '.' )) strcat( spec->file_name, ".exe" );
if (!spec->subsystem) spec->subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI;
break;
case LONG_OPT_DEBUG:
set_exec_mode( MODE_DEBUG );
break;
case LONG_OPT_LDCMD:
ld_command = xstrdup( optarg );
break;
case LONG_OPT_NMCMD:
nm_command = xstrdup( optarg );
break;
case LONG_OPT_RELAY16:
set_exec_mode( MODE_RELAY16 );
break;
case LONG_OPT_RELAY32:
set_exec_mode( MODE_RELAY32 );
break;
case LONG_OPT_SUBSYSTEM:
set_subsystem( optarg, spec );
break;
case LONG_OPT_VERSION:
printf( "winebuild version " PACKAGE_VERSION "\n" );
exit(0);
case LONG_OPT_PEDLL:
set_exec_mode( MODE_PEDLL );
spec_file_name = xstrdup( optarg );
set_dll_file_name( optarg, spec );
break;
case '?':
usage(1);
break;
}
}
return &argv[optind];
}
/* load all specified resource files */
static void load_resources( char *argv[], DLLSPEC *spec )
{
int i;
char **ptr, **last;
switch (spec->type)
{
case SPEC_WIN16:
for (i = 0; i < nb_res_files; i++) load_res16_file( res_files[i], spec );
break;
case SPEC_WIN32:
for (i = 0; i < nb_res_files; i++)
{
if (!load_res32_file( res_files[i], spec ))
fatal_error( "%s is not a valid Win32 resource file\n", res_files[i] );
}
/* load any resource file found in the remaining arguments */
for (ptr = last = argv; *ptr; ptr++)
{
if (!load_res32_file( *ptr, spec ))
*last++ = *ptr; /* not a resource file, keep it in the list */
}
*last = NULL;
break;
}
}
static int parse_input_file( DLLSPEC *spec )
{
FILE *input_file = open_input_file( NULL, spec_file_name );
char *extension = strrchr( spec_file_name, '.' );
if (extension && !strcmp( extension, ".def" ))
return parse_def_file( input_file, spec );
else
return parse_spec_file( input_file, spec );
close_input_file( input_file );
}
/*******************************************************************
* main
*/
int main(int argc, char **argv)
{
DLLSPEC *spec = alloc_dll_spec();
#ifdef SIGHUP
signal( SIGHUP, exit_on_signal );
#endif
signal( SIGTERM, exit_on_signal );
signal( SIGINT, exit_on_signal );
output_file = stdout;
argv = parse_options( argc, argv, spec );
switch(exec_mode)
{
case MODE_DLL:
spec->characteristics |= IMAGE_FILE_DLL;
load_resources( argv, spec );
if (!parse_input_file( spec )) break;
switch (spec->type)
{
case SPEC_WIN16:
fatal_error( "Win16 specs are not supported in ReactOS version of winebuild\n" );
break;
case SPEC_WIN32:
read_undef_symbols( argv );
BuildSpec32File( output_file, spec );
break;
default: assert(0);
}
break;
case MODE_EXE:
if (spec->type == SPEC_WIN16) fatal_error( "Cannot build 16-bit exe files\n" );
load_resources( argv, spec );
read_undef_symbols( argv );
BuildSpec32File( output_file, spec );
break;
case MODE_DEF:
if (argv[0]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[0] );
if (spec->type == SPEC_WIN16) fatal_error( "Cannot yet build .def file for 16-bit dlls\n" );
if (!parse_input_file( spec )) break;
BuildDef32File( output_file, spec );
break;
case MODE_DEBUG:
BuildDebugFile( output_file, current_src_dir, argv );
break;
case MODE_RELAY16:
fatal_error( "Win16 relays are not supported in ReactOS version of winebuild\n" );
break;
case MODE_RELAY32:
fatal_error( "Win32 relays are not supported in ReactOS version of winebuild\n" );
break;
case MODE_PEDLL:
if (argv[0]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[0] );
if (!parse_input_file( spec )) break;
BuildPedllFile( output_file, spec );
break;
default:
usage(1);
break;
}
if (nb_errors) exit(1);
if (output_file_name)
{
fclose( output_file );
output_file_name = NULL;
}
return 0;
}

View file

@ -0,0 +1,138 @@
/* Copyright (C) 1991, 1992, 1996, 1998 Free Software Foundation, Inc.
This file is derived from mkstemp.c from the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "config.h"
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_PROCESS_H
#include <process.h>
#endif
/* We need to provide a type for gcc_uint64_t. */
#ifdef __GNUC__
__extension__ typedef unsigned long long gcc_uint64_t;
#else
typedef unsigned long gcc_uint64_t;
#endif
#ifndef TMP_MAX
#define TMP_MAX 16384
#endif
/*
@deftypefn Replacement int mkstemps (char *@var{template}, int @var{suffix_len})
Generate a unique temporary file name from @var{template}.
@var{template} has the form:
@example
@var{path}/ccXXXXXX@var{suffix}
@end example
@var{suffix_len} tells us how long @var{suffix} is (it can be zero
length). The last six characters of @var{template} before @var{suffix}
must be @samp{XXXXXX}; they are replaced with a string that makes the
filename unique. Returns a file descriptor open on the file for
reading and writing.
@end deftypefn
*/
int
mkstemps (
char *template,
int suffix_len)
{
static const char letters[]
= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
static gcc_uint64_t value;
#ifdef HAVE_GETTIMEOFDAY
struct timeval tv;
#endif
char *XXXXXX;
size_t len;
int count;
len = strlen (template);
if ((int) len < 6 + suffix_len
|| strncmp (&template[len - 6 - suffix_len], "XXXXXX", 6))
{
return -1;
}
XXXXXX = &template[len - 6 - suffix_len];
#ifdef HAVE_GETTIMEOFDAY
/* Get some more or less random data. */
gettimeofday (&tv, NULL);
value += ((gcc_uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid ();
#else
value += getpid ();
#endif
for (count = 0; count < TMP_MAX; ++count)
{
gcc_uint64_t v = value;
int fd;
/* Fill in the random bits. */
XXXXXX[0] = letters[v % 62];
v /= 62;
XXXXXX[1] = letters[v % 62];
v /= 62;
XXXXXX[2] = letters[v % 62];
v /= 62;
XXXXXX[3] = letters[v % 62];
v /= 62;
XXXXXX[4] = letters[v % 62];
v /= 62;
XXXXXX[5] = letters[v % 62];
#ifdef VMS
fd = open (template, O_RDWR|O_CREAT|O_EXCL, 0600, "fop=tmd");
#else
fd = open (template, O_RDWR|O_CREAT|O_EXCL, 0600);
#endif
if (fd >= 0)
/* The file does not exist. */
return fd;
/* This is a random value. It is only necessary that the next
TMP_MAX values generated by adding 7777 to VALUE are different
with (module 2^32). */
value += 7777;
}
/* We return the null string if we can't find a unique file name. */
template[0] = '\0';
return -1;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,360 @@
/*
* Builtin dlls resource support
*
* Copyright 2000 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#include <fcntl.h>
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
#include "winglue.h"
#include "build.h"
#define ALIGNMENT 2 /* alignment for resource data */
#define ALIGN_MASK ((1 << ALIGNMENT) - 1)
/* Unicode string or integer id */
struct string_id
{
char *str; /* ptr to string */
WORD id; /* integer id if str is NULL */
};
/* descriptor for a resource */
struct resource
{
struct string_id type;
struct string_id name;
const void *data;
unsigned int data_size;
WORD memopt;
};
/* type level of the resource tree */
struct res_type
{
const struct string_id *type; /* type name */
const struct resource *res; /* first resource of this type */
unsigned int nb_names; /* total number of names */
};
/* top level of the resource tree */
struct res_tree
{
struct res_type *types; /* types array */
unsigned int nb_types; /* total number of types */
};
static const unsigned char *file_pos; /* current position in resource file */
static const unsigned char *file_end; /* end of resource file */
static const char *file_name; /* current resource file name */
inline static struct resource *add_resource( DLLSPEC *spec )
{
spec->resources = xrealloc( spec->resources, (spec->nb_resources + 1) * sizeof(*spec->resources) );
return &spec->resources[spec->nb_resources++];
}
static struct res_type *add_type( struct res_tree *tree, const struct resource *res )
{
struct res_type *type;
tree->types = xrealloc( tree->types, (tree->nb_types + 1) * sizeof(*tree->types) );
type = &tree->types[tree->nb_types++];
type->type = &res->type;
type->res = res;
type->nb_names = 0;
return type;
}
/* get the next byte from the current resource file */
static unsigned char get_byte(void)
{
unsigned char ret = *file_pos++;
if (file_pos > file_end) fatal_error( "%s is a truncated/corrupted file\n", file_name );
return ret;
}
/* get the next word from the current resource file */
static WORD get_word(void)
{
/* might not be aligned */
#ifdef WORDS_BIGENDIAN
unsigned char high = get_byte();
unsigned char low = get_byte();
#else
unsigned char low = get_byte();
unsigned char high = get_byte();
#endif
return low | (high << 8);
}
/* get the next dword from the current resource file */
static DWORD get_dword(void)
{
#ifdef WORDS_BIGENDIAN
WORD high = get_word();
WORD low = get_word();
#else
WORD low = get_word();
WORD high = get_word();
#endif
return low | (high << 16);
}
/* get a string from the current resource file */
static void get_string( struct string_id *str )
{
if (*file_pos == 0xff)
{
get_byte(); /* skip the 0xff */
str->str = NULL;
str->id = get_word();
}
else
{
char *p = xmalloc( (strlen(file_pos) + 1) );
str->str = p;
str->id = 0;
while ((*p++ = get_byte()));
}
}
/* load the next resource from the current file */
static void load_next_resource( DLLSPEC *spec )
{
struct resource *res = add_resource( spec );
get_string( &res->type );
get_string( &res->name );
res->memopt = get_word();
res->data_size = get_dword();
res->data = file_pos;
file_pos += res->data_size;
if (file_pos > file_end) fatal_error( "%s is a truncated/corrupted file\n", file_name );
}
/* load a Win16 .res file */
void load_res16_file( const char *name, DLLSPEC *spec )
{
int fd;
void *base;
struct stat st;
if ((fd = open( name, O_RDONLY )) == -1) fatal_perror( "Cannot open %s", name );
if ((fstat( fd, &st ) == -1)) fatal_perror( "Cannot stat %s", name );
if (!st.st_size) fatal_error( "%s is an empty file\n", name );
#ifdef HAVE_MMAP
if ((base = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 )) == (void*)-1)
#endif /* HAVE_MMAP */
{
base = xmalloc( st.st_size );
if (read( fd, base, st.st_size ) != st.st_size)
fatal_error( "Cannot read %s\n", name );
}
file_name = name;
file_pos = base;
file_end = file_pos + st.st_size;
while (file_pos < file_end) load_next_resource( spec );
}
/* compare two strings/ids */
static int cmp_string( const struct string_id *str1, const struct string_id *str2 )
{
if (!str1->str)
{
if (!str2->str) return str1->id - str2->id;
return 1; /* an id compares larger than a string */
}
if (!str2->str) return -1;
return strcasecmp( str1->str, str2->str );
}
/* compare two resources for sorting the resource directory */
/* resources are stored first by type, then by name */
static int cmp_res( const void *ptr1, const void *ptr2 )
{
const struct resource *res1 = ptr1;
const struct resource *res2 = ptr2;
int ret;
if ((ret = cmp_string( &res1->type, &res2->type ))) return ret;
return cmp_string( &res1->name, &res2->name );
}
/* build the 2-level (type,name) resource tree */
static struct res_tree *build_resource_tree( DLLSPEC *spec )
{
int i;
struct res_tree *tree;
struct res_type *type = NULL;
qsort( spec->resources, spec->nb_resources, sizeof(*spec->resources), cmp_res );
tree = xmalloc( sizeof(*tree) );
tree->types = NULL;
tree->nb_types = 0;
for (i = 0; i < spec->nb_resources; i++)
{
if (!i || cmp_string( &spec->resources[i].type, &spec->resources[i-1].type )) /* new type */
type = add_type( tree, &spec->resources[i] );
type->nb_names++;
}
return tree;
}
/* free the resource tree */
static void free_resource_tree( struct res_tree *tree )
{
free( tree->types );
free( tree );
}
inline static void put_byte( unsigned char **buffer, unsigned char val )
{
*(*buffer)++ = val;
}
inline static void put_word( unsigned char **buffer, WORD val )
{
#ifdef WORDS_BIGENDIAN
put_byte( buffer, HIBYTE(val) );
put_byte( buffer, LOBYTE(val) );
#else
put_byte( buffer, LOBYTE(val) );
put_byte( buffer, HIBYTE(val) );
#endif
}
/* output a string preceded by its length */
static void output_string( unsigned char **buffer, const char *str )
{
int len = strlen(str);
put_byte( buffer, len );
while (len--) put_byte( buffer, *str++ );
}
/* output the resource data */
int output_res16_data( FILE *outfile, DLLSPEC *spec )
{
const struct resource *res;
unsigned char *buffer, *p;
int i, total;
if (!spec->nb_resources) return 0;
for (i = total = 0, res = spec->resources; i < spec->nb_resources; i++, res++)
total += (res->data_size + ALIGN_MASK) & ~ALIGN_MASK;
buffer = p = xmalloc( total );
for (i = 0, res = spec->resources; i < spec->nb_resources; i++, res++)
{
memcpy( p, res->data, res->data_size );
p += res->data_size;
while ((int)p & ALIGN_MASK) *p++ = 0;
}
dump_bytes( outfile, buffer, total, "resource_data", 1 );
free( buffer );
return total;
}
/* output the resource definitions */
int output_res16_directory( unsigned char *buffer, DLLSPEC *spec )
{
int i, offset, res_offset = 0;
unsigned int j;
struct res_tree *tree;
const struct res_type *type;
const struct resource *res;
unsigned char *start = buffer;
tree = build_resource_tree( spec );
offset = 4; /* alignment + terminator */
offset += tree->nb_types * 8; /* typeinfo structures */
offset += spec->nb_resources * 12; /* nameinfo structures */
put_word( &buffer, ALIGNMENT );
/* type and name structures */
for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
{
if (type->type->str)
{
put_word( &buffer, offset );
offset += strlen(type->type->str) + 1;
}
else
put_word( &buffer, type->type->id | 0x8000 );
put_word( &buffer, type->nb_names );
put_word( &buffer, 0 );
put_word( &buffer, 0 );
for (j = 0, res = type->res; j < type->nb_names; j++, res++)
{
put_word( &buffer, res_offset >> ALIGNMENT );
put_word( &buffer, (res->data_size + ALIGN_MASK) >> ALIGNMENT );
put_word( &buffer, res->memopt );
if (res->name.str)
{
put_word( &buffer, offset );
offset += strlen(res->name.str) + 1;
}
else
put_word( &buffer, res->name.id | 0x8000 );
put_word( &buffer, 0 );
put_word( &buffer, 0 );
res_offset += (res->data_size + ALIGN_MASK) & ~ALIGN_MASK;
}
}
put_word( &buffer, 0 ); /* terminator */
/* name strings */
for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
{
if (type->type->str) output_string( &buffer, type->type->str );
for (j = 0, res = type->res; j < type->nb_names; j++, res++)
{
if (res->name.str) output_string( &buffer, res->name.str );
}
}
put_byte( &buffer, 0 ); /* names terminator */
if ((buffer - start) & 1) put_byte( &buffer, 0 ); /* align on word boundary */
free_resource_tree( tree );
return buffer - start;
}

View file

@ -0,0 +1,489 @@
/*
* Builtin dlls resource support
*
* Copyright 2000 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#include <fcntl.h>
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
#include "winglue.h"
#include "build.h"
/* Unicode string or integer id */
struct string_id
{
WCHAR *str; /* ptr to Unicode string */
WORD id; /* integer id if str is NULL */
};
/* descriptor for a resource */
struct resource
{
struct string_id type;
struct string_id name;
const void *data;
unsigned int data_size;
WORD lang;
};
/* name level of the resource tree */
struct res_name
{
const struct string_id *name; /* name */
const struct resource *res; /* resource */
int nb_languages; /* number of languages */
unsigned int name_offset; /* offset of name in resource dir */
};
/* type level of the resource tree */
struct res_type
{
const struct string_id *type; /* type name */
struct res_name *names; /* names array */
unsigned int nb_names; /* total number of names */
unsigned int nb_id_names; /* number of names that have a numeric id */
unsigned int name_offset; /* offset of type name in resource dir */
};
/* top level of the resource tree */
struct res_tree
{
struct res_type *types; /* types array */
unsigned int nb_types; /* total number of types */
};
static const unsigned char *file_pos; /* current position in resource file */
static const unsigned char *file_end; /* end of resource file */
static const char *file_name; /* current resource file name */
/* size of a resource directory with n entries */
#define RESDIR_SIZE(n) ((4 + 2 * (n)) * sizeof(int))
inline static struct resource *add_resource( DLLSPEC *spec )
{
spec->resources = xrealloc( spec->resources, (spec->nb_resources + 1) * sizeof(spec->resources[0]) );
return &spec->resources[spec->nb_resources++];
}
static inline unsigned int strlenW( const WCHAR *str )
{
const WCHAR *s = str;
while (*s) s++;
return s - str;
}
static inline int strcmpW( const WCHAR *str1, const WCHAR *str2 )
{
while (*str1 && (*str1 == *str2)) { str1++; str2++; }
return *str1 - *str2;
}
static struct res_name *add_name( struct res_type *type, const struct resource *res )
{
struct res_name *name;
type->names = xrealloc( type->names, (type->nb_names + 1) * sizeof(*type->names) );
name = &type->names[type->nb_names++];
name->name = &res->name;
name->res = res;
name->nb_languages = 1;
if (!name->name->str) type->nb_id_names++;
return name;
}
static struct res_type *add_type( struct res_tree *tree, const struct resource *res )
{
struct res_type *type;
tree->types = xrealloc( tree->types, (tree->nb_types + 1) * sizeof(*tree->types) );
type = &tree->types[tree->nb_types++];
type->type = &res->type;
type->names = NULL;
type->nb_names = 0;
type->nb_id_names = 0;
return type;
}
/* get the next word from the current resource file */
static WORD get_word(void)
{
WORD ret = *(const WORD *)file_pos;
file_pos += sizeof(WORD);
if (file_pos > file_end) fatal_error( "%s is a truncated file\n", file_name );
return ret;
}
/* get the next dword from the current resource file */
static DWORD get_dword(void)
{
DWORD ret = *(const DWORD *)file_pos;
file_pos += sizeof(DWORD);
if (file_pos > file_end) fatal_error( "%s is a truncated file\n", file_name );
return ret;
}
/* get a string from the current resource file */
static void get_string( struct string_id *str )
{
if (*(const WCHAR *)file_pos == 0xffff)
{
get_word(); /* skip the 0xffff */
str->str = NULL;
str->id = get_word();
}
else
{
WCHAR *p = xmalloc( (strlenW((const WCHAR*)file_pos) + 1) * sizeof(WCHAR) );
str->str = p;
str->id = 0;
while ((*p++ = get_word()));
}
}
/* check the file header */
/* all values must be zero except header size */
static int check_header(void)
{
if (get_dword()) return 0; /* data size */
if (get_dword() != 32) return 0; /* header size */
if (get_word() != 0xffff || get_word()) return 0; /* type, must be id 0 */
if (get_word() != 0xffff || get_word()) return 0; /* name, must be id 0 */
if (get_dword()) return 0; /* data version */
if (get_word()) return 0; /* mem options */
if (get_word()) return 0; /* language */
if (get_dword()) return 0; /* version */
if (get_dword()) return 0; /* characteristics */
return 1;
}
/* load the next resource from the current file */
static void load_next_resource( DLLSPEC *spec )
{
DWORD hdr_size;
struct resource *res = add_resource( spec );
res->data_size = (get_dword() + 3) & ~3;
hdr_size = get_dword();
if (hdr_size & 3) fatal_error( "%s header size not aligned\n", file_name );
res->data = file_pos - 2*sizeof(DWORD) + hdr_size;
get_string( &res->type );
get_string( &res->name );
if ((int)file_pos & 2) get_word(); /* align to dword boundary */
get_dword(); /* skip data version */
get_word(); /* skip mem options */
res->lang = get_word();
get_dword(); /* skip version */
get_dword(); /* skip characteristics */
file_pos = (const char *)res->data + res->data_size;
if (file_pos > file_end) fatal_error( "%s is a truncated file\n", file_name );
}
/* load a Win32 .res file */
int load_res32_file( const char *name, DLLSPEC *spec )
{
int fd, ret;
void *base;
struct stat st;
if ((fd = open( name, O_RDONLY )) == -1) fatal_perror( "Cannot open %s", name );
if ((fstat( fd, &st ) == -1)) fatal_perror( "Cannot stat %s", name );
if (!st.st_size) fatal_error( "%s is an empty file\n", name );
#ifdef HAVE_MMAP
if ((base = mmap( NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0 )) == (void*)-1)
#endif /* HAVE_MMAP */
{
base = xmalloc( st.st_size );
if (read( fd, base, st.st_size ) != st.st_size)
fatal_error( "Cannot read %s\n", name );
}
file_name = name;
file_pos = base;
file_end = file_pos + st.st_size;
if ((ret = check_header()))
{
while (file_pos < file_end) load_next_resource( spec );
}
close( fd );
return ret;
}
/* compare two unicode strings/ids */
static int cmp_string( const struct string_id *str1, const struct string_id *str2 )
{
if (!str1->str)
{
if (!str2->str) return str1->id - str2->id;
return 1; /* an id compares larger than a string */
}
if (!str2->str) return -1;
return strcmpW( str1->str, str2->str );
}
/* compare two resources for sorting the resource directory */
/* resources are stored first by type, then by name, then by language */
static int cmp_res( const void *ptr1, const void *ptr2 )
{
const struct resource *res1 = ptr1;
const struct resource *res2 = ptr2;
int ret;
if ((ret = cmp_string( &res1->type, &res2->type ))) return ret;
if ((ret = cmp_string( &res1->name, &res2->name ))) return ret;
return res1->lang - res2->lang;
}
/* build the 3-level (type,name,language) resource tree */
static struct res_tree *build_resource_tree( DLLSPEC *spec )
{
int i;
struct res_tree *tree;
struct res_type *type = NULL;
struct res_name *name = NULL;
qsort( spec->resources, spec->nb_resources, sizeof(*spec->resources), cmp_res );
tree = xmalloc( sizeof(*tree) );
tree->types = NULL;
tree->nb_types = 0;
for (i = 0; i < spec->nb_resources; i++)
{
if (!i || cmp_string( &spec->resources[i].type, &spec->resources[i-1].type )) /* new type */
{
type = add_type( tree, &spec->resources[i] );
name = add_name( type, &spec->resources[i] );
}
else if (cmp_string( &spec->resources[i].name, &spec->resources[i-1].name )) /* new name */
{
name = add_name( type, &spec->resources[i] );
}
else name->nb_languages++;
}
return tree;
}
/* free the resource tree */
static void free_resource_tree( struct res_tree *tree )
{
int i;
for (i = 0; i < tree->nb_types; i++) free( tree->types[i].names );
free( tree->types );
free( tree );
}
/* output a Unicode string */
static void output_string( FILE *outfile, const WCHAR *name )
{
int i, len = strlenW(name);
fprintf( outfile, "0x%04x", len );
for (i = 0; i < len; i++) fprintf( outfile, ", 0x%04x", name[i] );
fprintf( outfile, " /* " );
for (i = 0; i < len; i++) fprintf( outfile, "%c", isprint((char)name[i]) ? (char)name[i] : '?' );
fprintf( outfile, " */" );
}
/* output the resource definitions */
void output_resources( FILE *outfile, DLLSPEC *spec )
{
int i, j, k, nb_id_types;
unsigned int n, offset, data_offset;
struct res_tree *tree;
struct res_type *type;
struct res_name *name;
const struct resource *res;
if (!spec->nb_resources) return;
tree = build_resource_tree( spec );
/* resource data */
for (i = 0, res = spec->resources; i < spec->nb_resources; i++, res++)
{
const unsigned int *p = res->data;
int size = res->data_size / 4;
/* dump data as ints to ensure correct alignment */
fprintf( outfile, "static const unsigned int res_%d[%d] = {\n ", i, size );
for (j = 0; j < size - 1; j++, p++)
{
fprintf( outfile, "0x%08x,", *p );
if ((j % 8) == 7) fprintf( outfile, "\n " );
}
fprintf( outfile, "0x%08x\n};\n\n", *p );
}
/* directory structures */
fprintf( outfile, "struct res_dir {\n" );
fprintf( outfile, " unsigned int Characteristics;\n" );
fprintf( outfile, " unsigned int TimeDateStamp;\n" );
fprintf( outfile, " unsigned short MajorVersion, MinorVersion;\n" );
fprintf( outfile, " unsigned short NumerOfNamedEntries, NumberOfIdEntries;\n};\n\n" );
fprintf( outfile, "struct res_dir_entry {\n" );
fprintf( outfile, " unsigned int Name;\n" );
fprintf( outfile, " unsigned int OffsetToData;\n};\n\n" );
fprintf( outfile, "struct res_data_entry {\n" );
fprintf( outfile, " const unsigned int *OffsetToData;\n" );
fprintf( outfile, " unsigned int Size;\n" );
fprintf( outfile, " unsigned int CodePage;\n" );
fprintf( outfile, " unsigned int ResourceHandle;\n};\n\n" );
/* resource directory definition */
fprintf( outfile, "static struct res_struct{\n" );
fprintf( outfile, " struct res_dir type_dir;\n" );
fprintf( outfile, " struct res_dir_entry type_entries[%d];\n", tree->nb_types );
offset = RESDIR_SIZE( tree->nb_types );
for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
{
offset += RESDIR_SIZE( type->nb_names );
fprintf( outfile, " struct res_dir name_%d_dir;\n", i );
fprintf( outfile, " struct res_dir_entry name_%d_entries[%d];\n", i, type->nb_names );
for (n = 0, name = type->names; n < type->nb_names; n++, name++)
{
offset += RESDIR_SIZE( name->nb_languages );
fprintf( outfile, " struct res_dir lang_%d_%d_dir;\n", i, n );
fprintf( outfile, " struct res_dir_entry lang_%d_%d_entries[%d];\n",
i, n, name->nb_languages );
}
}
fprintf( outfile, " struct res_data_entry data_entries[%d];\n", spec->nb_resources );
offset += spec->nb_resources * 4 * sizeof(int);
for (i = nb_id_types = 0, type = tree->types; i < tree->nb_types; i++, type++)
{
if (type->type->str)
{
type->name_offset = offset | 0x80000000;
offset += (strlenW(type->type->str)+1) * sizeof(unsigned short);
fprintf( outfile, " unsigned short type_%d_name[%d];\n",
i, strlenW(type->type->str)+1 );
}
else
{
type->name_offset = type->type->id;
nb_id_types++;
}
for (n = 0, name = type->names; n < type->nb_names; n++, name++)
{
if (name->name->str)
{
name->name_offset = offset | 0x80000000;
offset += (strlenW(name->name->str)+1) * sizeof(unsigned short);
fprintf( outfile, " unsigned short name_%d_%d_name[%d];\n",
i, n, strlenW(name->name->str)+1 );
}
else name->name_offset = name->name->id;
}
}
/* resource directory contents */
fprintf( outfile, "} resources = {\n" );
fprintf( outfile, " { 0, 0, 0, 0, %d, %d },\n", tree->nb_types - nb_id_types, nb_id_types );
/* dump the type directory */
offset = RESDIR_SIZE( tree->nb_types );
fprintf( outfile, " {\n" );
for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
{
fprintf( outfile, " { 0x%08x, 0x%08x },\n", type->name_offset, offset | 0x80000000 );
offset += RESDIR_SIZE( type->nb_names );
for (n = 0, name = type->names; n < type->nb_names; n++, name++)
offset += RESDIR_SIZE( name->nb_languages );
}
fprintf( outfile, " },\n" );
data_offset = offset;
offset = RESDIR_SIZE( tree->nb_types );
/* dump the names and languages directories */
for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
{
fprintf( outfile, " { 0, 0, 0, 0, %d, %d }, /* name_%d_dir */\n {\n",
type->nb_names - type->nb_id_names, type->nb_id_names, i );
offset += RESDIR_SIZE( type->nb_names );
for (n = 0, name = type->names; n < type->nb_names; n++, name++)
{
fprintf( outfile, " { 0x%08x, 0x%08x },\n", name->name_offset, offset | 0x80000000 );
offset += RESDIR_SIZE( name->nb_languages );
}
fprintf( outfile, " },\n" );
for (n = 0, name = type->names; n < type->nb_names; n++, name++)
{
fprintf( outfile, " { 0, 0, 0, 0, 0, %d }, /* lang_%d_%d_dir */\n {\n",
name->nb_languages, i, n );
for (k = 0, res = name->res; k < name->nb_languages; k++, res++)
{
fprintf( outfile, " { 0x%04x, 0x%08x },\n",
res->lang, data_offset + (res - spec->resources) * 4 * sizeof(int) );
}
fprintf( outfile, " },\n" );
}
}
/* dump the resource data entries */
fprintf( outfile, " {\n" );
for (i = 0, res = spec->resources; i < spec->nb_resources; i++, res++)
{
fprintf( outfile, " { res_%d, sizeof(res_%d), 0, 0 }, /* %08x */\n", i, i,
data_offset + i * 4 * sizeof(int) );
}
/* dump the name strings */
for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
{
if (type->type->str)
{
fprintf( outfile, " },\n { " );
output_string( outfile, type->type->str );
}
for (n = 0, name = type->names; n < type->nb_names; n++, name++)
{
if (name->name->str)
{
fprintf( outfile, " },\n { " );
output_string( outfile, name->name->str );
}
}
}
fprintf( outfile, " }\n};\n\n" );
free_resource_tree( tree );
}

View file

@ -0,0 +1,832 @@
/*
* 16-bit spec files
*
* Copyright 1993 Robert J. Amstadt
* Copyright 1995 Martin von Loewis
* Copyright 1995, 1996, 1997 Alexandre Julliard
* Copyright 1997 Eric Youngdale
* Copyright 1999 Ulrich Weigand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <assert.h>
#include <ctype.h>
#include "wine/exception.h"
#include "stackframe.h"
#include "builtin16.h"
#include "module.h"
#include "build.h"
/*******************************************************************
* get_cs
*/
#ifdef __i386__
static inline unsigned short get_cs(void)
{
unsigned short res;
#ifdef __GNUC__
__asm__("movw %%cs,%w0" : "=r"(res));
#elif defined(_MSC_VER)
__asm { mov res, cs }
#else
res = 0;
#endif
return res;
}
#endif /* __i386__ */
/*******************************************************************
* output_file_header
*
* Output a file header with the common declarations we need.
*/
static void output_file_header( FILE *outfile )
{
output_standard_file_header( outfile );
fprintf( outfile, "extern struct\n{\n" );
fprintf( outfile, " void *base[8192];\n" );
fprintf( outfile, " unsigned long limit[8192];\n" );
fprintf( outfile, " unsigned char flags[8192];\n" );
fprintf( outfile, "} wine_ldt_copy;\n\n" );
#ifdef __i386__
fprintf( outfile, "#define __stdcall __attribute__((__stdcall__))\n\n" );
#else
fprintf( outfile, "#define __stdcall\n\n" );
#endif
}
/*******************************************************************
* StoreVariableCode
*
* Store a list of ints into a byte array.
*/
static int StoreVariableCode( unsigned char *buffer, int size, ORDDEF *odp )
{
int i;
switch(size)
{
case 1:
for (i = 0; i < odp->u.var.n_values; i++)
buffer[i] = odp->u.var.values[i];
break;
case 2:
for (i = 0; i < odp->u.var.n_values; i++)
((unsigned short *)buffer)[i] = odp->u.var.values[i];
break;
case 4:
for (i = 0; i < odp->u.var.n_values; i++)
((unsigned int *)buffer)[i] = odp->u.var.values[i];
break;
}
return odp->u.var.n_values * size;
}
/*******************************************************************
* BuildModule16
*
* Build the in-memory representation of a 16-bit NE module, and dump it
* as a byte stream into the assembly code.
*/
static int BuildModule16( FILE *outfile, int max_code_offset,
int max_data_offset, DLLSPEC *spec )
{
int i;
char *buffer;
NE_MODULE *pModule;
SEGTABLEENTRY *pSegment;
OFSTRUCT *pFileInfo;
BYTE *pstr;
ET_BUNDLE *bundle = 0;
ET_ENTRY entry;
/* Module layout:
* NE_MODULE Module
* OFSTRUCT File information
* SEGTABLEENTRY Segment 1 (code)
* SEGTABLEENTRY Segment 2 (data)
* WORD[2] Resource table (empty)
* BYTE[2] Imported names (empty)
* BYTE[n] Resident names table
* BYTE[n] Entry table
*/
buffer = xmalloc( 0x10000 );
memset( buffer, 0, 0x10000 );
pModule = (NE_MODULE *)buffer;
pModule->magic = IMAGE_OS2_SIGNATURE;
pModule->count = 1;
pModule->next = 0;
pModule->flags = NE_FFLAGS_SINGLEDATA | NE_FFLAGS_BUILTIN | NE_FFLAGS_LIBMODULE;
pModule->dgroup = 2;
pModule->heap_size = spec->heap_size;
pModule->stack_size = 0;
pModule->ip = 0;
pModule->cs = 0;
pModule->sp = 0;
pModule->ss = 0;
pModule->seg_count = 2;
pModule->modref_count = 0;
pModule->nrname_size = 0;
pModule->modref_table = 0;
pModule->nrname_fpos = 0;
pModule->moveable_entries = 0;
pModule->alignment = 0;
pModule->truetype = 0;
pModule->os_flags = NE_OSFLAGS_WINDOWS;
pModule->misc_flags = 0;
pModule->dlls_to_init = 0;
pModule->nrname_handle = 0;
pModule->min_swap_area = 0;
pModule->expected_version = 0;
pModule->module32 = 0;
pModule->self = 0;
pModule->self_loading_sel = 0;
/* File information */
pFileInfo = (OFSTRUCT *)(pModule + 1);
pModule->fileinfo = (int)pFileInfo - (int)pModule;
memset( pFileInfo, 0, sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName) );
pFileInfo->cBytes = sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName)
+ strlen(spec->file_name);
strcpy( pFileInfo->szPathName, spec->file_name );
pstr = (char *)pFileInfo + pFileInfo->cBytes + 1;
/* Segment table */
pstr = (char *)(((long)pstr + 3) & ~3);
pSegment = (SEGTABLEENTRY *)pstr;
pModule->seg_table = (int)pSegment - (int)pModule;
pSegment->filepos = 0;
pSegment->size = max_code_offset;
pSegment->flags = 0;
pSegment->minsize = max_code_offset;
pSegment->hSeg = 0;
pSegment++;
pModule->dgroup_entry = (int)pSegment - (int)pModule;
pSegment->filepos = 0;
pSegment->size = max_data_offset;
pSegment->flags = NE_SEGFLAGS_DATA;
pSegment->minsize = max_data_offset;
pSegment->hSeg = 0;
pSegment++;
/* Resource table */
pstr = (char *)pSegment;
pstr = (char *)(((long)pstr + 3) & ~3);
pModule->res_table = (int)pstr - (int)pModule;
pstr += output_res16_directory( pstr, spec );
/* Imported names table */
pstr = (char *)(((long)pstr + 3) & ~3);
pModule->import_table = (int)pstr - (int)pModule;
*pstr++ = 0;
*pstr++ = 0;
/* Resident names table */
pstr = (char *)(((long)pstr + 3) & ~3);
pModule->name_table = (int)pstr - (int)pModule;
/* First entry is module name */
*pstr = strlen( spec->dll_name );
strcpy( pstr + 1, spec->dll_name );
strupper( pstr + 1 );
pstr += *pstr + 1;
*pstr++ = 0;
*pstr++ = 0;
/* Store all ordinals */
for (i = 1; i <= spec->limit; i++)
{
ORDDEF *odp = spec->ordinals[i];
WORD ord = i;
if (!odp || !odp->name[0]) continue;
*pstr = strlen( odp->name );
strcpy( pstr + 1, odp->name );
strupper( pstr + 1 );
pstr += *pstr + 1;
memcpy( pstr, &ord, sizeof(WORD) );
pstr += sizeof(WORD);
}
*pstr++ = 0;
/* Entry table */
pstr = (char *)(((long)pstr + 3) & ~3);
pModule->entry_table = (int)pstr - (int)pModule;
for (i = 1; i <= spec->limit; i++)
{
int selector = 0;
ORDDEF *odp = spec->ordinals[i];
if (!odp) continue;
switch (odp->type)
{
case TYPE_CDECL:
case TYPE_PASCAL:
case TYPE_VARARGS:
case TYPE_STUB:
selector = 1; /* Code selector */
break;
case TYPE_VARIABLE:
selector = 2; /* Data selector */
break;
case TYPE_ABS:
selector = 0xfe; /* Constant selector */
break;
default:
selector = 0; /* Invalid selector */
break;
}
if ( !selector )
continue;
if ( bundle && bundle->last+1 == i )
bundle->last++;
else
{
pstr = (char *)(((long)pstr + 1) & ~1);
if ( bundle )
bundle->next = (char *)pstr - (char *)pModule;
bundle = (ET_BUNDLE *)pstr;
bundle->first = i-1;
bundle->last = i;
bundle->next = 0;
pstr += sizeof(ET_BUNDLE);
}
/* FIXME: is this really correct ?? */
entry.type = 0xff; /* movable */
entry.flags = 3; /* exported & public data */
entry.segnum = selector;
entry.offs = odp->offset;
memcpy( pstr, &entry, sizeof(ET_ENTRY) );
pstr += sizeof(ET_ENTRY);
}
*pstr++ = 0;
/* Dump the module content */
pstr = (char *)(((long)pstr + 3) & ~3);
dump_bytes( outfile, (char *)pModule, (int)pstr - (int)pModule, "Module", 0 );
return (int)pstr - (int)pModule;
}
#ifdef __i386__
/*******************************************************************
* BuildCallFrom16Func
*
* Build a 16-bit-to-Wine callback glue function.
*
* The generated routines are intended to be used as argument conversion
* routines to be called by the CallFrom16... core. Thus, the prototypes of
* the generated routines are (see also CallFrom16):
*
* extern WORD WINAPI PREFIX_CallFrom16_C_word_xxx( FARPROC func, LPBYTE args );
* extern LONG WINAPI PREFIX_CallFrom16_C_long_xxx( FARPROC func, LPBYTE args );
* extern void WINAPI PREFIX_CallFrom16_C_regs_xxx( FARPROC func, LPBYTE args,
* CONTEXT86 *context );
*
* where 'C' is the calling convention ('p' for pascal or 'c' for cdecl),
* and each 'x' is an argument ('w'=word, 's'=signed word, 'l'=long,
* 'p'=linear pointer, 't'=linear pointer to null-terminated string,
* 'T'=segmented pointer to null-terminated string).
*
* The generated routines fetch the arguments from the 16-bit stack (pointed
* to by 'args'); the offsets of the single argument values are computed
* according to the calling convention and the argument types. Then, the
* 32-bit entry point is called with these arguments.
*
* For register functions, the arguments (if present) are converted just
* the same as for normal functions, but in addition the CONTEXT86 pointer
* filled with the current register values is passed to the 32-bit routine.
*/
static void BuildCallFrom16Func( FILE *outfile, const char *profile, const char *prefix )
{
int i, pos, argsize = 0;
int short_ret = 0;
int reg_func = 0;
int usecdecl = 0;
int varargs = 0;
const char *args = profile + 7;
const char *ret_type;
/* Parse function type */
if (!strncmp( "c_", profile, 2 )) usecdecl = 1;
else if (!strncmp( "v_", profile, 2 )) varargs = usecdecl = 1;
else if (strncmp( "p_", profile, 2 ))
{
fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
return;
}
if (!strncmp( "word_", profile + 2, 5 )) short_ret = 1;
else if (!strncmp( "regs_", profile + 2, 5 )) reg_func = 1;
else if (strncmp( "long_", profile + 2, 5 ))
{
fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
return;
}
for ( i = 0; args[i]; i++ )
switch ( args[i] )
{
case 'w': /* word */
case 's': /* s_word */
argsize += 2;
break;
case 'l': /* long or segmented pointer */
case 'T': /* segmented pointer to null-terminated string */
case 'p': /* linear pointer */
case 't': /* linear pointer to null-terminated string */
argsize += 4;
break;
}
ret_type = reg_func? "void" : short_ret ? "unsigned short" : "unsigned int";
fprintf( outfile, "typedef %s (%s*proc_%s_t)( ",
ret_type, usecdecl ? "" : "__stdcall ", profile );
args = profile + 7;
for ( i = 0; args[i]; i++ )
{
if ( i ) fprintf( outfile, ", " );
switch (args[i])
{
case 'w': fprintf( outfile, "unsigned short" ); break;
case 's': fprintf( outfile, "short" ); break;
case 'l': case 'T': fprintf( outfile, "unsigned int" ); break;
case 'p': case 't': fprintf( outfile, "void *" ); break;
}
}
if (reg_func || varargs)
fprintf( outfile, "%svoid *", i? ", " : "" );
else if ( !i )
fprintf( outfile, "void" );
fprintf( outfile, " );\n" );
fprintf( outfile, "static %s __stdcall __wine_%s_CallFrom16_%s( proc_%s_t proc, unsigned char *args%s )\n",
ret_type, make_c_identifier(prefix), profile, profile,
reg_func? ", void *context" : "" );
fprintf( outfile, "{\n %sproc(\n", reg_func ? "" : "return " );
args = profile + 7;
pos = !usecdecl? argsize : 0;
for ( i = 0; args[i]; i++ )
{
if ( i ) fprintf( outfile, ",\n" );
fprintf( outfile, " " );
switch (args[i])
{
case 'w': /* word */
if ( !usecdecl ) pos -= 2;
fprintf( outfile, "*(unsigned short *)(args+%d)", pos );
if ( usecdecl ) pos += 2;
break;
case 's': /* s_word */
if ( !usecdecl ) pos -= 2;
fprintf( outfile, "*(short *)(args+%d)", pos );
if ( usecdecl ) pos += 2;
break;
case 'l': /* long or segmented pointer */
case 'T': /* segmented pointer to null-terminated string */
if ( !usecdecl ) pos -= 4;
fprintf( outfile, "*(unsigned int *)(args+%d)", pos );
if ( usecdecl ) pos += 4;
break;
case 'p': /* linear pointer */
case 't': /* linear pointer to null-terminated string */
if ( !usecdecl ) pos -= 4;
fprintf( outfile, "((char*)wine_ldt_copy.base[*(unsigned short*)(args+%d) >> 3] + *(unsigned short*)(args+%d))",
pos + 2, pos );
if ( usecdecl ) pos += 4;
break;
default:
fprintf( stderr, "Unknown arg type '%c'\n", args[i] );
}
}
if ( reg_func )
fprintf( outfile, "%s context", i? ",\n" : "" );
else if (varargs)
fprintf( outfile, "%s args + %d", i? ",\n" : "", argsize );
fprintf( outfile, " );\n}\n\n" );
}
#endif
/*******************************************************************
* get_function_name
*/
static const char *get_function_name( const ORDDEF *odp )
{
static char buffer[80];
sprintf( buffer, "%s_%s_%s",
(odp->type == TYPE_PASCAL) ? "p" :
(odp->type == TYPE_VARARGS) ? "v" : "c",
(odp->flags & FLAG_REGISTER) ? "regs" :
(odp->flags & FLAG_RET16) ? "word" : "long",
odp->u.func.arg_types );
return buffer;
}
/*******************************************************************
* Spec16TypeCompare
*/
static int Spec16TypeCompare( const void *e1, const void *e2 )
{
const ORDDEF *odp1 = *(const ORDDEF * const *)e1;
const ORDDEF *odp2 = *(const ORDDEF * const *)e2;
int retval;
int type1 = odp1->type;
int type2 = odp2->type;
if (type1 == TYPE_STUB) type1 = TYPE_CDECL;
if (type2 == TYPE_STUB) type2 = TYPE_CDECL;
if ((retval = type1 - type2) != 0) return retval;
type1 = odp1->flags & (FLAG_RET16|FLAG_REGISTER);
type2 = odp2->flags & (FLAG_RET16|FLAG_REGISTER);
if ((retval = type1 - type2) != 0) return retval;
return strcmp( odp1->u.func.arg_types, odp2->u.func.arg_types );
}
/*******************************************************************
* output_stub_funcs
*
* Output the functions for stub entry points
*/
static void output_stub_funcs( FILE *outfile, const DLLSPEC *spec )
{
int i;
char *p;
for (i = 0; i <= spec->limit; i++)
{
ORDDEF *odp = spec->ordinals[i];
if (!odp || odp->type != TYPE_STUB) continue;
fprintf( outfile, "#ifdef __GNUC__\n" );
fprintf( outfile, "static void __wine_unimplemented( const char *func ) __attribute__((noreturn));\n" );
fprintf( outfile, "#endif\n" );
fprintf( outfile, "static void __wine_unimplemented( const char *func )\n{\n" );
fprintf( outfile, " struct exc_record {\n" );
fprintf( outfile, " unsigned int code, flags;\n" );
fprintf( outfile, " void *rec, *addr;\n" );
fprintf( outfile, " unsigned int params;\n" );
fprintf( outfile, " const void *info[15];\n" );
fprintf( outfile, " } rec;\n\n" );
fprintf( outfile, " extern void __stdcall RtlRaiseException( struct exc_record * );\n\n" );
fprintf( outfile, " rec.code = 0x%08x;\n", EXCEPTION_WINE_STUB );
fprintf( outfile, " rec.flags = %d;\n", EH_NONCONTINUABLE );
fprintf( outfile, " rec.rec = 0;\n" );
fprintf( outfile, " rec.params = 2;\n" );
fprintf( outfile, " rec.info[0] = \"%s\";\n", spec->file_name );
fprintf( outfile, " rec.info[1] = func;\n" );
fprintf( outfile, "#ifdef __GNUC__\n" );
fprintf( outfile, " rec.addr = __builtin_return_address(1);\n" );
fprintf( outfile, "#else\n" );
fprintf( outfile, " rec.addr = 0;\n" );
fprintf( outfile, "#endif\n" );
fprintf( outfile, " for (;;) RtlRaiseException( &rec );\n}\n\n" );
break;
}
for (i = 0; i <= spec->limit; i++)
{
ORDDEF *odp = spec->ordinals[i];
if (!odp || odp->type != TYPE_STUB) continue;
odp->link_name = xrealloc( odp->link_name, strlen(odp->name) + 13 );
strcpy( odp->link_name, "__wine_stub_" );
strcat( odp->link_name, odp->name );
for (p = odp->link_name; *p; p++) if (!isalnum(*p)) *p = '_';
fprintf( outfile, "static void %s(void) { __wine_unimplemented(\"%s\"); }\n",
odp->link_name, odp->name );
}
}
/*******************************************************************
* BuildSpec16File
*
* Build a Win16 assembly file from a spec file.
*/
void BuildSpec16File( FILE *outfile, DLLSPEC *spec )
{
ORDDEF **type, **typelist;
int i, nFuncs, nTypes;
int code_offset, data_offset, module_size, res_size;
unsigned char *data;
char constructor[100], destructor[100];
#ifdef __i386__
unsigned short code_selector = get_cs();
#endif
/* File header */
output_file_header( outfile );
fprintf( outfile, "extern unsigned short __wine_call_from_16_word();\n" );
fprintf( outfile, "extern unsigned int __wine_call_from_16_long();\n" );
fprintf( outfile, "extern void __wine_call_from_16_regs();\n" );
fprintf( outfile, "extern void __wine_call_from_16_thunk();\n" );
data = (unsigned char *)xmalloc( 0x10000 );
memset( data, 0, 16 );
data_offset = 16;
if (!spec->dll_name) /* set default name from file name */
{
char *p;
spec->dll_name = xstrdup( spec->file_name );
if ((p = strrchr( spec->dll_name, '.' ))) *p = 0;
}
output_stub_funcs( outfile, spec );
/* Build sorted list of all argument types, without duplicates */
typelist = (ORDDEF **)calloc( spec->limit+1, sizeof(ORDDEF *) );
for (i = nFuncs = 0; i <= spec->limit; i++)
{
ORDDEF *odp = spec->ordinals[i];
if (!odp) continue;
switch (odp->type)
{
case TYPE_CDECL:
case TYPE_PASCAL:
case TYPE_VARARGS:
case TYPE_STUB:
typelist[nFuncs++] = odp;
default:
break;
}
}
qsort( typelist, nFuncs, sizeof(ORDDEF *), Spec16TypeCompare );
i = nTypes = 0;
while ( i < nFuncs )
{
typelist[nTypes++] = typelist[i++];
while ( i < nFuncs && Spec16TypeCompare( typelist + i, typelist + nTypes-1 ) == 0 )
i++;
}
/* Output CallFrom16 routines needed by this .spec file */
#ifdef __i386__
for ( i = 0; i < nTypes; i++ )
{
char profile[101];
strcpy( profile, get_function_name( typelist[i] ));
BuildCallFrom16Func( outfile, profile, spec->file_name );
}
#endif
/* Output the DLL functions prototypes */
for (i = 0; i <= spec->limit; i++)
{
ORDDEF *odp = spec->ordinals[i];
if (!odp) continue;
switch(odp->type)
{
case TYPE_CDECL:
case TYPE_PASCAL:
case TYPE_VARARGS:
fprintf( outfile, "extern void %s();\n", odp->link_name );
break;
default:
break;
}
}
/* Output code segment */
fprintf( outfile, "\n#include \"pshpack1.h\"\n" );
fprintf( outfile, "\nstatic struct code_segment\n{\n" );
fprintf( outfile, " struct {\n" );
#ifdef __i386__
fprintf( outfile, " unsigned char pushl;\n" ); /* pushl $relay */
fprintf( outfile, " void *relay;\n" );
fprintf( outfile, " unsigned char lcall;\n" ); /* lcall __FLATCS__:glue */
fprintf( outfile, " void *glue;\n" );
fprintf( outfile, " unsigned short flatcs;\n" );
#endif
fprintf( outfile, " unsigned short lret;\n" ); /* lret $args */
fprintf( outfile, " unsigned short args;\n" );
fprintf( outfile, " unsigned int arg_types[2];\n" );
fprintf( outfile, " } call[%d];\n", nTypes );
fprintf( outfile, " struct {\n" );
#ifdef __i386__
fprintf( outfile, " unsigned short pushw_bp;\n" ); /* pushw %bp */
fprintf( outfile, " unsigned char pushl;\n" ); /* pushl $target */
#endif
fprintf( outfile, " void (*target)();\n" );
fprintf( outfile, " unsigned short call;\n" ); /* call CALLFROM16 */
fprintf( outfile, " short callfrom16;\n" );
fprintf( outfile, " } entry[%d];\n", nFuncs );
fprintf( outfile, "} code_segment =\n{\n {\n" );
code_offset = 0;
for ( i = 0; i < nTypes; i++ )
{
char profile[101], *arg;
unsigned int arg_types[2];
int j, argsize = 0;
strcpy( profile, get_function_name( typelist[i] ));
if ( typelist[i]->type == TYPE_PASCAL )
for ( arg = typelist[i]->u.func.arg_types; *arg; arg++ )
switch ( *arg )
{
case 'w': /* word */
case 's': /* s_word */
argsize += 2;
break;
case 'l': /* long or segmented pointer */
case 'T': /* segmented pointer to null-terminated string */
case 'p': /* linear pointer */
case 't': /* linear pointer to null-terminated string */
argsize += 4;
break;
}
/* build the arg types bit fields */
arg_types[0] = arg_types[1] = 0;
for (j = 0; typelist[i]->u.func.arg_types[j]; j++)
{
int type = 0;
switch(typelist[i]->u.func.arg_types[j])
{
case 'w': type = ARG_WORD; break;
case 's': type = ARG_SWORD; break;
case 'l': type = ARG_LONG; break;
case 'p': type = ARG_PTR; break;
case 't': type = ARG_STR; break;
case 'T': type = ARG_SEGSTR; break;
}
arg_types[j / 10] |= type << (3 * (j % 10));
}
if (typelist[i]->flags & FLAG_REGISTER) arg_types[0] |= ARG_REGISTER;
if (typelist[i]->flags & FLAG_RET16) arg_types[0] |= ARG_RET16;
#ifdef __i386__
fprintf( outfile, " { 0x68, __wine_%s_CallFrom16_%s, 0x9a, __wine_call_from_16_%s,\n",
make_c_identifier(spec->file_name), profile,
(typelist[i]->flags & FLAG_REGISTER) ? "regs":
(typelist[i]->flags & FLAG_RET16) ? "word" : "long" );
if (argsize)
fprintf( outfile, " 0x%04x, 0xca66, %d, { 0x%08x, 0x%08x } },\n",
code_selector, argsize, arg_types[0], arg_types[1] );
else
fprintf( outfile, " 0x%04x, 0xcb66, 0x9090, { 0x%08x, 0x%08x } },\n",
code_selector, arg_types[0], arg_types[1] );
#else
if (argsize)
fprintf( outfile, " { 0xca66, %d, { 0x%08x, 0x%08x } },\n",
argsize, arg_types[0], arg_types[1] );
else
fprintf( outfile, " { 0xcb66, 0x9090, { 0x%08x, 0x%08x } },\n",
arg_types[0], arg_types[1] );
#endif
code_offset += sizeof(CALLFROM16);
}
fprintf( outfile, " },\n {\n" );
for (i = 0; i <= spec->limit; i++)
{
ORDDEF *odp = spec->ordinals[i];
if (!odp) continue;
switch (odp->type)
{
case TYPE_ABS:
odp->offset = LOWORD(odp->u.abs.value);
break;
case TYPE_VARIABLE:
odp->offset = data_offset;
data_offset += StoreVariableCode( data + data_offset, 4, odp);
break;
case TYPE_CDECL:
case TYPE_PASCAL:
case TYPE_VARARGS:
case TYPE_STUB:
type = bsearch( &odp, typelist, nTypes, sizeof(ORDDEF *), Spec16TypeCompare );
assert( type );
fprintf( outfile, " /* %s.%d */ ", spec->dll_name, i );
#ifdef __i386__
fprintf( outfile, "{ 0x5566, 0x68, %s, 0xe866, %d /* %s */ },\n",
#else
fprintf( outfile, "{ %s, 0xe866, %d, /* %s */ },\n",
#endif
odp->link_name,
(type-typelist)*sizeof(CALLFROM16) -
(code_offset + sizeof(ENTRYPOINT16)),
get_function_name( odp ) );
odp->offset = code_offset;
code_offset += sizeof(ENTRYPOINT16);
break;
default:
fprintf(stderr,"build: function type %d not available for Win16\n",
odp->type);
exit(1);
}
}
fprintf( outfile, " }\n};\n" );
/* Output data segment */
dump_bytes( outfile, data, data_offset, "Data_Segment", 0 );
/* Build the module */
module_size = BuildModule16( outfile, code_offset, data_offset, spec );
res_size = output_res16_data( outfile, spec );
/* Output the DLL descriptor */
fprintf( outfile, "#include \"poppack.h\"\n\n" );
fprintf( outfile, "static const struct dll_descriptor\n{\n" );
fprintf( outfile, " unsigned char *module_start;\n" );
fprintf( outfile, " int module_size;\n" );
fprintf( outfile, " struct code_segment *code_start;\n" );
fprintf( outfile, " unsigned char *data_start;\n" );
fprintf( outfile, " const char *owner;\n" );
fprintf( outfile, " const unsigned char *rsrc;\n" );
fprintf( outfile, "} descriptor =\n{\n" );
fprintf( outfile, " Module,\n" );
fprintf( outfile, " sizeof(Module),\n" );
fprintf( outfile, " &code_segment,\n" );
fprintf( outfile, " Data_Segment,\n" );
fprintf( outfile, " \"%s\",\n", spec->owner_name );
fprintf( outfile, " %s\n", res_size ? "resource_data" : "0" );
fprintf( outfile, "};\n" );
/* Output the DLL constructor */
sprintf( constructor, "__wine_spec_%s_init", make_c_identifier(spec->file_name) );
sprintf( destructor, "__wine_spec_%s_fini", make_c_identifier(spec->file_name) );
output_dll_init( outfile, constructor, destructor );
fprintf( outfile,
"void %s(void)\n"
"{\n"
" extern void __wine_register_dll_16( const struct dll_descriptor *descr );\n"
" __wine_register_dll_16( &descriptor );\n"
"}\n", constructor );
fprintf( outfile,
"void %s(void)\n"
"{\n"
" extern void __wine_unregister_dll_16( const struct dll_descriptor *descr );\n"
" __wine_unregister_dll_16( &descriptor );\n"
"}\n", destructor );
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,415 @@
/*
* Small utility functions for winebuild
*
* Copyright 2000 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#if !defined(WIN32)
#undef strdup
#endif
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "build.h"
void *xmalloc (size_t size)
{
void *res;
res = malloc (size ? size : 1);
if (res == NULL)
{
fprintf (stderr, "Virtual memory exhausted.\n");
exit (1);
}
return res;
}
void *xrealloc (void *ptr, size_t size)
{
void *res = realloc (ptr, size);
if (res == NULL)
{
fprintf (stderr, "Virtual memory exhausted.\n");
exit (1);
}
return res;
}
char *xstrdup( const char *str )
{
char *res = strdup( str );
if (!res)
{
fprintf (stderr, "Virtual memory exhausted.\n");
exit (1);
}
return res;
}
char *strupper(char *s)
{
char *p;
for (p = s; *p; p++) *p = toupper(*p);
return s;
}
void fatal_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 );
}
else fprintf( stderr, "winebuild: " );
vfprintf( stderr, msg, valist );
va_end( valist );
exit(1);
}
void fatal_perror( 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 );
perror( " " );
va_end( valist );
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;
if (!display_warnings) return;
va_start( valist, msg );
if (input_file_name)
{
fprintf( stderr, "%s:", input_file_name );
if (current_line)
fprintf( stderr, "%d:", current_line );
fputc( ' ', stderr );
}
fprintf( stderr, "warning: " );
vfprintf( stderr, msg, valist );
va_end( valist );
}
/* output a standard header for generated files */
void output_standard_file_header( FILE *outfile )
{
if (input_file_name)
fprintf( outfile, "/* File generated automatically from %s; do not edit! */\n",
input_file_name );
else
fprintf( outfile, "/* File generated automatically; do not edit! */\n" );
fprintf( outfile,
"/* This file can be copied, modified and distributed without restriction. */\n\n" );
}
/* dump a byte stream into the assembly code */
void dump_bytes( FILE *outfile, const unsigned char *data, int len,
const char *label, int constant )
{
int i;
fprintf( outfile, "\nstatic %sunsigned char %s[%d] = {",
constant ? "const " : "", label, len );
for (i = 0; i < len; i++)
{
if (!(i & 7)) fprintf( outfile, "\n " );
fprintf( outfile, "0x%02x", *data++ );
if (i < len - 1) fprintf( outfile, "," );
}
fprintf( outfile, "\n};\n" );
}
/*******************************************************************
* open_input_file
*
* Open a file in the given srcdir and set the input_file_name global variable.
*/
FILE *open_input_file( const char *srcdir, const char *name )
{
char *fullname;
FILE *file = fopen( name, "r" );
if (!file && srcdir)
{
fullname = xmalloc( strlen(srcdir) + strlen(name) + 2 );
strcpy( fullname, srcdir );
strcat( fullname, "/" );
strcat( fullname, name );
file = fopen( fullname, "r" );
}
else fullname = xstrdup( name );
if (!file) fatal_error( "Cannot open file '%s'\n", fullname );
input_file_name = fullname;
current_line = 1;
return file;
}
/*******************************************************************
* close_input_file
*
* Close the current input file (must have been opened with open_input_file).
*/
void close_input_file( FILE *file )
{
fclose( file );
free( input_file_name );
input_file_name = NULL;
current_line = 0;
}
/*******************************************************************
* remove_stdcall_decoration
*
* Remove a possible @xx suffix from a function name.
* Return the numerical value of the suffix, or -1 if none.
*/
int remove_stdcall_decoration( char *name )
{
char *p, *end = strrchr( name, '@' );
if (!end || !end[1] || end == name) return -1;
/* make sure all the rest is digits */
for (p = end + 1; *p; p++) if (!isdigit(*p)) return -1;
*end = 0;
return atoi( end + 1 );
}
/*******************************************************************
* alloc_dll_spec
*
* Create a new dll spec file descriptor
*/
DLLSPEC *alloc_dll_spec(void)
{
DLLSPEC *spec;
spec = xmalloc( sizeof(*spec) );
spec->file_name = NULL;
spec->dll_name = NULL;
spec->owner_name = NULL;
spec->init_func = NULL;
spec->type = SPEC_WIN32;
spec->base = MAX_ORDINALS;
spec->limit = 0;
spec->stack_size = 0;
spec->heap_size = 0;
spec->nb_entry_points = 0;
spec->alloc_entry_points = 0;
spec->nb_names = 0;
spec->nb_resources = 0;
spec->characteristics = 0;
spec->subsystem = 0;
spec->subsystem_major = 4;
spec->subsystem_minor = 0;
spec->entry_points = NULL;
spec->names = NULL;
spec->ordinals = NULL;
spec->resources = NULL;
return spec;
}
/*******************************************************************
* free_dll_spec
*
* Free dll spec file descriptor
*/
void free_dll_spec( DLLSPEC *spec )
{
int i;
for (i = 0; i < spec->nb_entry_points; i++)
{
ORDDEF *odp = &spec->entry_points[i];
free( odp->name );
free( odp->export_name );
free( odp->link_name );
}
free( spec->file_name );
free( spec->dll_name );
free( spec->owner_name );
free( spec->init_func );
free( spec->entry_points );
free( spec->names );
free( spec->ordinals );
free( spec->resources );
free( spec );
}
/*******************************************************************
* make_c_identifier
*
* Map a string to a valid C identifier.
*/
const char *make_c_identifier( const char *str )
{
static char buffer[256];
char *p;
for (p = buffer; *str && p < buffer+sizeof(buffer)-1; p++, str++)
{
if (isalnum(*str)) *p = *str;
else *p = '_';
}
*p = 0;
return buffer;
}
/*****************************************************************
* Function: get_alignment
*
* Description:
* According to the info page for gas, the .align directive behaves
* differently on different systems. On some architectures, the
* argument of a .align directive is the number of bytes to pad to, so
* to align on an 8-byte boundary you'd say
* .align 8
* On other systems, the argument is "the number of low-order zero bits
* that the location counter must have after advancement." So to
* align on an 8-byte boundary you'd say
* .align 3
*
* The reason gas is written this way is that it's trying to mimick
* native assemblers for the various architectures it runs on. gas
* provides other directives that work consistantly across
* architectures, but of course we want to work on all arches with or
* without gas. Hence this function.
*
*
* Parameters:
* alignBoundary -- the number of bytes to align to.
* If we're on an architecture where
* the assembler requires a 'number
* of low-order zero bits' as a
* .align argument, then this number
* must be a power of 2.
*
*/
int get_alignment(int alignBoundary)
{
#if defined(__powerpc__) || defined(__ALPHA__)
int n = 0;
switch(alignBoundary)
{
case 2:
n = 1;
break;
case 4:
n = 2;
break;
case 8:
n = 3;
break;
case 16:
n = 4;
break;
case 32:
n = 5;
break;
case 64:
n = 6;
break;
case 128:
n = 7;
break;
case 256:
n = 8;
break;
case 512:
n = 9;
break;
case 1024:
n = 10;
break;
case 2048:
n = 11;
break;
case 4096:
n = 12;
break;
case 8192:
n = 13;
break;
case 16384:
n = 14;
break;
case 32768:
n = 15;
break;
case 65536:
n = 16;
break;
default:
fatal_error("Alignment to %d-byte boundary not supported on this architecture.\n",
alignBoundary);
}
return n;
#elif defined(__i386__) || defined(__sparc__)
return alignBoundary;
#else
#error "How does the '.align' assembler directive work on your architecture?"
#endif
}

View file

@ -0,0 +1,434 @@
.\" -*- nroff -*-
.TH WINEBUILD 1 "March 2003" "@PACKAGE_STRING@" "Wine dll builder"
.SH NAME
winebuild \- Wine dll builder
.SH SYNOPSIS
.BI winebuild\ [options]\ [input\ files]
.SH DESCRIPTION
.B winebuild
generates the C and assembly files that are necessary to build a Wine
dll, which is basically a Win32 dll encapsulated inside a Unix
library.
.PP
.B winebuild
has different modes, depending on what kind of file it is asked to
generate. The mode is specified by one of the mode options specified
below. In addition to the mode option, various other command-line
option can be specified, as described in the \fBOPTIONS\fR section.
.SH "MODE OPTIONS"
You have to specify exactly one of the following options, depending on
what you want winebuild to generate.
.TP
.BI \--dll= filename
Build a C file from a .spec file (see \fBSPEC FILE SYNTAX\fR for
details), or from a standard Windows .def file. The resulting C file
must be compiled and linked to the other object files to build a
working Wine dll.
.br
In that mode, the
.I input files
should be the list of all object files that will be linked into the
final dll, to allow
.B winebuild
to get the list of all undefined symbols that need to be imported from
other dlls.
.TP
.BI \--exe= name
Build a C file for the named executable. This is basically the same as
the --dll mode except that it doesn't require a .spec file as input,
since an executable doesn't export functions. The resulting C file
must be compiled and linked to the other object files to build a
working Wine executable, and all the other object files must be listed
as
.I input files.
.TP
.BI \--def= file.spec
Build a .def file from a spec file. This is used when building dlls
with a PE (Win32) compiler.
.TP
.B \--debug
Build a C file containing the definitions for debugging channels. In
that mode the
.I input files
should be a list of C files to search for debug channel
definitions. The resulting C file must be compiled and linked with the
dll.
.TP
.B \--relay16
Generate the assembly code for the 16-bit relay routines. This is for
Wine internal usage only, you should never need to use this option.
.TP
.B \--relay32
Generate the assembly code for the 32-bit relay routines. This is for
Wine internal usage only, you should never need to use this option.
.SH OPTIONS
.TP
.BI \-C,\ --source-dir= directory
Change to the specified directory before reading source files. Only
meaningful in
.BR \--debug\ mode.
.TP
.BI \-D\ symbol
Ignored for compatibility with the C compiler.
.TP
.BI \-e,\ --entry= function
Specify the module entry point function; if not specified, the default
is
.B DllMain
for dlls, and
.B WinMain
for executables (if
.B WinMain
is not defined, the standard C
.B main
is used instead). This is only valid for Win32 modules.
.TP
.BI \-f\ flags
Ignored for compatibility with the C compiler.
.TP
.BI \-F,\ --filename= filename
Set the file name of the module. The default is to use the base name
of the spec file (without any extension).
.TP
.B \-h, --help
Display a usage message and exit.
.TP
.BI \-H,\ --heap= size
Specify the size of the module local heap in bytes (only valid for
Win16 modules); default is no local heap.
.TP
.BI \-i,\ --ignore= [-]symbol[,[-]symbol]
Specify a list of symbols that should be ignored when resolving
undefined symbols against the imported libraries. This forces these
symbols to be resolved from the Unix C library (or from another Unix
library linked with the application). If a symbol is prefixed by '-'
it is removed from the list instead of being added; a stand-alone '-'
clears the whole list.
.TP
.BI \-I\ directory
Ignored for compatibility with the C compiler.
.TP
.B \-k, --kill-at
Remove the stdcall decorations from the symbol names in the
generated .def file. Only meaningful in \fB--def\fR mode.
.TP
.BI \-K\ flags
Ignored for compatibility with the C compiler.
.TP
.BI \--ld-cmd= ld-command
Specify the command to use to link the object files; the default is
\fBld\fR.
.TP
.BI \--nm-cmd= nm-command
Specify the command to use to get the list of undefined symbols; the
default is \fBnm\fR.
.TP
.BI \-L,\ --library-path= directory
Append the specified directory to the list of directories that are
searched for import libraries.
.TP
.BI \-l,\ --library= name
Import the specified library, looking for a corresponding
\fIlibname.def\fR file in the directories specified with the \fB-L\fR
option.
.TP
.BI \-d,\ --delay-lib= name
Same as the \fB-l\fR option, but import the specified library in
delayed mode (i.e. the library won't be loaded until a function
imported from it is actually called).
.TP
.BI \-M,\ --main-module= module
Specify that we are building a 16-bit dll, that will ultimately be
linked together with the 32-bit dll specified in \fImodule\fR. Only
meaningful in \fB--dll\fR mode.
.TP
.BI \-N,\ --dll-name= dllname
Set the internal name of the module. It is only used in Win16
modules. The default is to use the base name of the spec file (without
any extension). This is used for KERNEL, since it lives in
KRNL386.EXE. It shouldn't be needed otherwise.
.TP
.BI \-o,\ --output= file
Set the name of the output file (default is standard output).
.TP
.BI \-r,\ --res= rsrc.res
Load resources from the specified binary resource file. The
\fIrsrc.res\fR can be produced from a source resource file with
.BR wrc(1)
(or with a Windows resource compiler).
.br
This option is only necessary for Win16 resource files, the Win32 ones
can simply listed as
.I input files
and will automatically be handled correctly (though the
.B \-r
option will also work for Win32 files).
.TP
.BI --subsystem= subsystem[:major[.minor]]
Set the subsystem of the executable, which can be one of the following:
.br
.B console
for a command line executable,
.br
.B windows
for a graphical executable,
.br
.B native
for a native-mode dll.
.br
The entry point of a command line executable is a normal C \fBmain\fR
function. A \fBwmain\fR function can be used instead if you need the
argument array to use Unicode strings. A graphical executable has a
\fBWinMain\fR entry point.
.br
Optionally a major and minor subsystem version can also be specified;
the default subsystem version is 4.0.
.TP
.B \--version
Display the program version and exit.
.TP
.B \-w, --warnings
Turn on warnings.
.SH "SPEC FILE SYNTAX"
.SS "General syntax"
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) \ [ handler ]
.br
.IB ordinal\ variable
.RI [ flags ]\ exportname \ \fB(\fR\ [ data... ] \ \fB)
.br
.IB ordinal\ extern
.RI [ flags ]\ exportname \ [ symbolname ]
.br
.IB ordinal\ stub
.RI [ flags ]\ exportname
.br
.IB ordinal\ equate
.RI [ flags ]\ exportname\ data
.br
.BI #\ comments
.PP
Declarations must fit on a single line, except if the end of line is
escaped using a backslash character. The
.B #
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 '@'
for automatic ordinal allocation (Win32 only).
.PP
.I flags
is a series of optional flags, preceded by a '-' character. The
supported flags are:
.RS
.TP
.B -norelay
The entry point is not displayed in relay debugging traces (Win32
only).
.TP
.B -noname
The entry point will be imported by ordinal instead of by name.
.TP
.B -ret16
The function returns a 16-bit value (Win16 only).
.TP
.B -ret64
The function returns a 64-bit value (Win32 only).
.TP
.B -i386
The entry point is only available on i386 platforms.
.TP
.B -register
The function uses CPU register to pass arguments.
.TP
.B -private
The function cannot be imported from other dlls, it can only be
accessed through GetProcAddress.
.SS "Function ordinals"
Syntax:
.br
.I ordinal functype
.RI [ flags ]\ exportname \ \fB(\fR\ [ args... ] \ \fB) \ [ handler ]
.br
This declaration defines a function entry point. The prototype defined by
.IR exportname \ \fB(\fR\ [ args... ] \ \fB)
specifies the name available for dynamic linking and the format of the
arguments. '@' can be used instead of
.I exportname
for ordinal-only exports.
.PP
.I functype
should be one of:
.RS
.TP
.B stdcall
for a normal Win32 function
.TP
.B pascal
for a normal Win16 function
.TP
.B cdecl
for a Win16 or Win32 function using the C calling convention
.TP
.B varargs
for a Win16 or Win32 function using the C calling convention with a
variable number of arguments
.RE
.PP
.I args
should be one or several of:
.RS
.TP
.B word
(16-bit unsigned value)
.TP
.B s_word
(16-bit signed word)
.TP
.B long
(32-bit value)
.TP
.B double
(64-bit value)
.TP
.B ptr
(linear pointer)
.TP
.B str
(linear pointer to a null-terminated ASCII string)
.TP
.B wstr
(linear pointer to a null-terminated Unicode string)
.TP
.B segptr
(segmented pointer)
.TP
.B segstr
(segmented pointer to a null-terminated ASCII string).
.HP
.RB Only\ ptr ,\ str ,\ wstr ,\ long\ and\ double
are valid for Win32 functions.
.RE
.PP
.I handler
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). 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 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, specify
the function as
.B varargs
and declare it in the C file with a '...' parameter for a Win32
function, or with an extra VA_LIST16 argument for a Win16 function.
See the wsprintf* functions in user.exe.spec and user32.spec for an
example.
.SS "Variable ordinals"
Syntax:
.br
.IB ordinal\ variable
.RI [ flags ]\ exportname \ \fB(\fR\ [ data... ] \ \fB)
.PP
This declaration defines data storage as 32-bit words at the ordinal
specified.
.I exportname
will be the name available for dynamic
linking.
.I data
can be a decimal number or a hex number preceeded by "0x". The
following example defines the variable VariableA at ordinal 2 and
containing 4 ints:
.IP
2 variable VariableA(-1 0xff 0 0)
.PP
This declaration only works in Win16 spec files. In Win32 you should
use
.B extern
instead (see below).
.SS "Extern ordinals"
Syntax:
.br
.IB ordinal\ extern
.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.
.I exportname
will point to the symbol
.I symbolname
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). If
.I symbolname
is not specified, it is assumed to be identical to
.I exportname.
.SS "Stub ordinals"
Syntax:
.br
.IB ordinal\ stub
.RI [ flags ]\ exportname
.PP
This declaration defines a stub function. It makes the name and
ordinal available for dynamic linking, but will terminate execution
with an error message if the function is ever called.
.SS "Equate ordinals"
Syntax:
.br
.IB ordinal\ equate
.RI [ flags ]\ exportname\ data
.PP
This declaration defines an ordinal as an absolute value.
.I exportname
will be the name available for dynamic linking.
.I data
can be a decimal number or a hex number preceeded by "0x".
.SH AUTHORS
.B winebuild
has been worked on by many people over the years. The main authors are
Robert J. Amstadt, Alexandre Julliard, Martin von Loewis, Ulrich
Weigand and Eric Youngdale. Many other Wine developers have
contributed, please check the file Changelog in the Wine distribution
for the complete details.
.SH BUGS
It is not yet possible to use a PE-format dll in an import
specification; only Wine dlls can be imported.
.PP
If you find a bug, please submit a bug report at
.UR http://bugs.winehq.org
.B http://bugs.winehq.org.
.UE
.SH AVAILABILITY
.B winebuild
is part of the wine distribution, which is available through WineHQ,
the
.B wine
development headquarters, at
.UR http://www.winehq.org/
.B http://www.winehq.org/.
.UE
.SH "SEE ALSO"
.BR wine (1),
.BR wrc (1).

View file

@ -0,0 +1,31 @@
#ifndef _WINGLUE_H
#define _WINGLUE_H
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef unsigned short WCHAR;
#define LOBYTE(w) ((BYTE)(w))
#define HIBYTE(w) ((BYTE)(((WORD)(w)>>8)&0xFF))
#define DLL_PROCESS_ATTACH 1
#define DLL_PROCESS_DETACH 0
#define IMAGE_FILE_DLL 8192
#define IMAGE_SUBSYSTEM_NATIVE 1
#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2
#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
#define IMAGE_FILE_MACHINE_I386 332
#define IMAGE_NT_SIGNATURE 0x00004550
#define IMAGE_NT_OPTIONAL_HDR_MAGIC 0x10b
#ifndef max
#define max(a,b) ((a)>(b)?(a):(b))
#endif
#ifndef min
#define min(a,b) ((a)<(b)?(a):(b))
#endif
#endif /* _WINGLUE_H */