123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299 |
- /*
- * Spec file parser
- *
- * Copyright 1993 Robert J. Amstadt
- * Copyright 1995 Martin von Loewis
- * Copyright 1995, 1996, 1997, 2004 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
- #include "config.h"
- #include <assert.h>
- #include <ctype.h>
- #include <stdarg.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "build.h"
- int current_line = 0;
- static char ParseBuffer[512];
- static char TokenBuffer[512];
- static char *ParseNext = ParseBuffer;
- static FILE *input_file;
- static const char *separator_chars;
- static const char *comment_chars;
- /* valid characters in ordinal names */
- static const char valid_ordname_chars[] = "/$:-_@?<>abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- static const char * const TypeNames[TYPE_NBTYPES] =
- {
- "variable", /* TYPE_VARIABLE */
- "pascal", /* TYPE_PASCAL */
- "equate", /* TYPE_ABS */
- "stub", /* TYPE_STUB */
- "stdcall", /* TYPE_STDCALL */
- "cdecl", /* TYPE_CDECL */
- "varargs", /* TYPE_VARARGS */
- "extern" /* TYPE_EXTERN */
- };
- static const char * const FlagNames[] =
- {
- "norelay", /* FLAG_NORELAY */
- "noname", /* FLAG_NONAME */
- "ret16", /* FLAG_RET16 */
- "ret64", /* FLAG_RET64 */
- "register", /* FLAG_REGISTER */
- "private", /* FLAG_PRIVATE */
- "ordinal", /* FLAG_ORDINAL */
- "thiscall", /* FLAG_THISCALL */
- "fastcall", /* FLAG_FASTCALL */
- "syscall", /* FLAG_SYSCALL */
- "import", /* FLAG_IMPORT */
- NULL
- };
- static const char * const ArgNames[ARG_MAXARG + 1] =
- {
- "word", /* ARG_WORD */
- "s_word", /* ARG_SWORD */
- "segptr", /* ARG_SEGPTR */
- "segstr", /* ARG_SEGSTR */
- "long", /* ARG_LONG */
- "ptr", /* ARG_PTR */
- "str", /* ARG_STR */
- "wstr", /* ARG_WSTR */
- "int64", /* ARG_INT64 */
- "int128", /* ARG_INT128 */
- "float", /* ARG_FLOAT */
- "double" /* ARG_DOUBLE */
- };
- static int IsNumberString(const char *s)
- {
- while (*s) if (!isdigit(*s++)) return 0;
- return 1;
- }
- static inline int is_token_separator( char ch )
- {
- return strchr( separator_chars, ch ) != NULL;
- }
- static inline int is_token_comment( char ch )
- {
- return strchr( comment_chars, ch ) != NULL;
- }
- /* get the next line from the input file, or return 0 if at eof */
- static int get_next_line(void)
- {
- ParseNext = ParseBuffer;
- current_line++;
- return (fgets(ParseBuffer, sizeof(ParseBuffer), input_file) != NULL);
- }
- static const char * GetToken( int allow_eol )
- {
- char *p;
- char *token = TokenBuffer;
- for (;;)
- {
- /* remove initial white space */
- p = ParseNext;
- while (isspace(*p)) p++;
- if (*p == '\\' && p[1] == '\n') /* line continuation */
- {
- if (!get_next_line())
- {
- if (!allow_eol) error( "Unexpected end of file\n" );
- return NULL;
- }
- }
- else break;
- }
- if ((*p == '\0') || is_token_comment(*p))
- {
- if (!allow_eol) error( "Declaration not terminated properly\n" );
- return NULL;
- }
- /*
- * Find end of token.
- */
- if (is_token_separator(*p))
- {
- /* a separator is always a complete token */
- *token++ = *p++;
- }
- else while (*p != '\0' && !is_token_separator(*p) && !isspace(*p))
- {
- if (*p == '\\') p++;
- if (*p) *token++ = *p++;
- }
- *token = '\0';
- ParseNext = p;
- return TokenBuffer;
- }
- static ORDDEF *add_entry_point( DLLSPEC *spec )
- {
- ORDDEF *ret;
- if (spec->nb_entry_points == spec->alloc_entry_points)
- {
- spec->alloc_entry_points += 128;
- spec->entry_points = xrealloc( spec->entry_points,
- spec->alloc_entry_points * sizeof(*spec->entry_points) );
- }
- ret = &spec->entry_points[spec->nb_entry_points++];
- memset( ret, 0, sizeof(*ret) );
- return ret;
- }
- /*******************************************************************
- * parse_spec_variable
- *
- * Parse a variable definition in a .spec file.
- */
- static int parse_spec_variable( ORDDEF *odp, DLLSPEC *spec )
- {
- char *endptr;
- unsigned int *value_array;
- int n_values;
- int value_array_size;
- const char *token;
- if (spec->type == SPEC_WIN32)
- {
- error( "'variable' not supported in Win32, use 'extern' instead\n" );
- return 0;
- }
- if (!(token = GetToken(0))) return 0;
- if (*token != '(')
- {
- error( "Expected '(' got '%s'\n", token );
- return 0;
- }
- n_values = 0;
- value_array_size = 25;
- value_array = xmalloc(sizeof(*value_array) * value_array_size);
- for (;;)
- {
- if (!(token = GetToken(0)))
- {
- free( value_array );
- return 0;
- }
- if (*token == ')')
- break;
- value_array[n_values++] = strtoul(token, &endptr, 0);
- if (n_values == value_array_size)
- {
- value_array_size += 25;
- value_array = xrealloc(value_array,
- sizeof(*value_array) * value_array_size);
- }
- if (endptr == NULL || *endptr != '\0')
- {
- error( "Expected number value, got '%s'\n", token );
- free( value_array );
- return 0;
- }
- }
- odp->u.var.n_values = n_values;
- odp->u.var.values = xrealloc(value_array, sizeof(*value_array) * n_values);
- return 1;
- }
- /*******************************************************************
- * parse_spec_arguments
- *
- * Parse the arguments of an entry point.
- */
- static int parse_spec_arguments( ORDDEF *odp, DLLSPEC *spec, int optional )
- {
- const char *token;
- unsigned int i, arg;
- int is_win32 = (spec->type == SPEC_WIN32) || (odp->flags & FLAG_EXPORT32);
- if (!(token = GetToken( optional ))) return optional;
- if (*token != '(')
- {
- error( "Expected '(' got '%s'\n", token );
- return 0;
- }
- odp->u.func.nb_args = 0;
- for (i = 0; i < MAX_ARGUMENTS; i++)
- {
- if (!(token = GetToken(0))) return 0;
- if (*token == ')')
- break;
- for (arg = 0; arg <= ARG_MAXARG; arg++)
- if (!strcmp( ArgNames[arg], token )) break;
- if (arg > ARG_MAXARG)
- {
- error( "Unknown argument type '%s'\n", token );
- return 0;
- }
- if (is_win32) switch (arg)
- {
- case ARG_WORD:
- case ARG_SWORD:
- case ARG_SEGPTR:
- case ARG_SEGSTR:
- error( "Argument type '%s' only allowed for Win16\n", token );
- return 0;
- }
- odp->u.func.args[i] = arg;
- }
- if (*token != ')')
- {
- error( "Too many arguments\n" );
- return 0;
- }
- odp->u.func.nb_args = i;
- if (odp->flags & FLAG_THISCALL)
- {
- if (odp->type != TYPE_STDCALL)
- {
- error( "A thiscall function must use the stdcall convention\n" );
- return 0;
- }
- if (!i || odp->u.func.args[0] != ARG_PTR)
- {
- error( "First argument of a thiscall function must be a pointer\n" );
- return 0;
- }
- }
- if (odp->flags & FLAG_FASTCALL)
- {
- if (odp->type != TYPE_STDCALL)
- {
- error( "A fastcall function must use the stdcall convention\n" );
- return 0;
- }
- if (!i || (odp->u.func.args[0] != ARG_PTR && odp->u.func.args[0] != ARG_LONG))
- {
- error( "First argument of a fastcall function must be a pointer or integer\n" );
- return 0;
- }
- if (i > 1 && odp->u.func.args[1] != ARG_PTR && odp->u.func.args[1] != ARG_LONG)
- {
- error( "Second argument of a fastcall function must be a pointer or integer\n" );
- return 0;
- }
- }
- if (odp->flags & FLAG_SYSCALL)
- {
- if (odp->type != TYPE_STDCALL && odp->type != TYPE_CDECL)
- {
- error( "A syscall function must use either the stdcall or the cdecl convention\n" );
- return 0;
- }
- }
- return 1;
- }
- /*******************************************************************
- * parse_spec_export
- *
- * Parse an exported function definition in a .spec file.
- */
- static int parse_spec_export( ORDDEF *odp, DLLSPEC *spec )
- {
- const char *token;
- int is_win32 = (spec->type == SPEC_WIN32) || (odp->flags & FLAG_EXPORT32);
- if (!is_win32 && odp->type == TYPE_STDCALL)
- {
- error( "'stdcall' not supported for Win16\n" );
- return 0;
- }
- if (is_win32 && odp->type == TYPE_PASCAL)
- {
- error( "'pascal' not supported for Win32\n" );
- return 0;
- }
- if (!parse_spec_arguments( odp, spec, 0 )) return 0;
- if (odp->type == TYPE_VARARGS)
- odp->flags |= FLAG_NORELAY; /* no relay debug possible for varags entry point */
- if (target.cpu != CPU_i386)
- odp->flags &= ~(FLAG_THISCALL | FLAG_FASTCALL);
- if (!(token = GetToken(1)))
- {
- if (!strcmp( odp->name, "@" ))
- {
- error( "Missing handler name for anonymous function\n" );
- return 0;
- }
- odp->link_name = xstrdup( odp->name );
- }
- else
- {
- odp->link_name = xstrdup( token );
- if (strchr( odp->link_name, '.' ))
- {
- if (!is_win32)
- {
- error( "Forwarded functions not supported for Win16\n" );
- return 0;
- }
- odp->flags |= FLAG_FORWARD;
- }
- }
- return 1;
- }
- /*******************************************************************
- * parse_spec_equate
- *
- * Parse an 'equate' definition in a .spec file.
- */
- static int parse_spec_equate( ORDDEF *odp, DLLSPEC *spec )
- {
- char *endptr;
- int value;
- const char *token;
- if (spec->type == SPEC_WIN32)
- {
- error( "'equate' not supported for Win32\n" );
- return 0;
- }
- if (!(token = GetToken(0))) return 0;
- value = strtol(token, &endptr, 0);
- if (endptr == NULL || *endptr != '\0')
- {
- error( "Expected number value, got '%s'\n", token );
- return 0;
- }
- if (value < -0x8000 || value > 0xffff)
- {
- error( "Value %d for absolute symbol doesn't fit in 16 bits\n", value );
- value = 0;
- }
- odp->u.abs.value = value;
- return 1;
- }
- /*******************************************************************
- * parse_spec_stub
- *
- * Parse a 'stub' definition in a .spec file
- */
- static int parse_spec_stub( ORDDEF *odp, DLLSPEC *spec )
- {
- odp->u.func.nb_args = -1;
- odp->link_name = xstrdup("");
- return parse_spec_arguments( odp, spec, 1 );
- }
- /*******************************************************************
- * parse_spec_extern
- *
- * Parse an 'extern' definition in a .spec file.
- */
- static int parse_spec_extern( ORDDEF *odp, DLLSPEC *spec )
- {
- const char *token;
- if (spec->type == SPEC_WIN16)
- {
- error( "'extern' not supported for Win16, use 'variable' instead\n" );
- return 0;
- }
- if (!(token = GetToken(1)))
- {
- if (!strcmp( odp->name, "@" ))
- {
- error( "Missing handler name for anonymous extern\n" );
- return 0;
- }
- odp->link_name = xstrdup( odp->name );
- }
- else
- {
- odp->link_name = xstrdup( token );
- if (strchr( odp->link_name, '.' )) odp->flags |= FLAG_FORWARD;
- }
- return 1;
- }
- /*******************************************************************
- * parse_spec_flags
- *
- * Parse the optional flags for an entry point in a .spec file.
- */
- static const char *parse_spec_flags( DLLSPEC *spec, ORDDEF *odp, const char *token )
- {
- unsigned int i, cpu_mask = 0;
- do
- {
- token++;
- if (!strncmp( token, "arch=", 5))
- {
- char *args = xstrdup( token + 5 );
- char *cpu_name = strtok( args, "," );
- while (cpu_name)
- {
- if (!strcmp( cpu_name, "win32" ))
- {
- if (spec->type == SPEC_WIN32)
- odp->flags |= FLAG_CPU_WIN32;
- else
- odp->flags |= FLAG_EXPORT32;
- }
- else if (!strcmp( cpu_name, "win64" ))
- odp->flags |= FLAG_CPU_WIN64;
- else
- {
- int cpu = get_cpu_from_name( cpu_name + (cpu_name[0] == '!') );
- if (cpu == -1)
- {
- error( "Unknown architecture '%s'\n", cpu_name );
- return NULL;
- }
- if (cpu_name[0] == '!') cpu_mask |= FLAG_CPU( cpu );
- else odp->flags |= FLAG_CPU( cpu );
- }
- cpu_name = strtok( NULL, "," );
- }
- free( args );
- }
- else if (!strcmp( token, "i386" )) /* backwards compatibility */
- {
- odp->flags |= FLAG_CPU(CPU_i386);
- }
- else
- {
- for (i = 0; FlagNames[i]; i++)
- if (!strcmp( FlagNames[i], token )) break;
- if (!FlagNames[i])
- {
- error( "Unknown flag '%s'\n", token );
- return NULL;
- }
- switch (1 << i)
- {
- case FLAG_RET16:
- case FLAG_REGISTER:
- if (spec->type == SPEC_WIN32)
- error( "Flag '%s' is not supported in Win32\n", FlagNames[i] );
- break;
- case FLAG_RET64:
- case FLAG_THISCALL:
- case FLAG_FASTCALL:
- if (spec->type == SPEC_WIN16)
- error( "Flag '%s' is not supported in Win16\n", FlagNames[i] );
- break;
- }
- odp->flags |= 1 << i;
- }
- token = GetToken(0);
- } while (token && *token == '-');
- if (cpu_mask) odp->flags |= FLAG_CPU_MASK & ~cpu_mask;
- return token;
- }
- /*******************************************************************
- * parse_spec_ordinal
- *
- * Parse an ordinal definition in a .spec file.
- */
- static int parse_spec_ordinal( int ordinal, DLLSPEC *spec )
- {
- const char *token;
- size_t len;
- ORDDEF *odp = add_entry_point( spec );
- if (!(token = GetToken(0))) goto error;
- for (odp->type = 0; odp->type < TYPE_NBTYPES; odp->type++)
- if (TypeNames[odp->type] && !strcmp( token, TypeNames[odp->type] ))
- break;
- if (odp->type >= TYPE_NBTYPES)
- {
- if (!strcmp( token, "thiscall" )) /* for backwards compatibility */
- {
- odp->type = TYPE_STDCALL;
- odp->flags |= FLAG_THISCALL;
- }
- else
- {
- error( "Expected type after ordinal, found '%s' instead\n", token );
- goto error;
- }
- }
- if (!(token = GetToken(0))) goto error;
- if (*token == '-' && !(token = parse_spec_flags( spec, odp, token ))) goto error;
- if (ordinal == -1 && spec->type != SPEC_WIN32 && !(odp->flags & FLAG_EXPORT32))
- {
- error( "'@' ordinals not supported for Win16\n" );
- goto error;
- }
- odp->name = xstrdup( token );
- odp->lineno = current_line;
- odp->ordinal = ordinal;
- len = strspn( odp->name, valid_ordname_chars );
- if (len < strlen( odp->name ))
- {
- error( "Character '%c' is not allowed in exported name '%s'\n", odp->name[len], odp->name );
- goto error;
- }
- switch(odp->type)
- {
- case TYPE_VARIABLE:
- if (!parse_spec_variable( odp, spec )) goto error;
- break;
- case TYPE_PASCAL:
- case TYPE_STDCALL:
- case TYPE_VARARGS:
- case TYPE_CDECL:
- if (!parse_spec_export( odp, spec )) goto error;
- break;
- case TYPE_ABS:
- if (!parse_spec_equate( odp, spec )) goto error;
- break;
- case TYPE_STUB:
- if (!parse_spec_stub( odp, spec )) goto error;
- break;
- case TYPE_EXTERN:
- if (!parse_spec_extern( odp, spec )) goto error;
- break;
- default:
- assert( 0 );
- }
- if ((odp->flags & FLAG_CPU_MASK) && !(odp->flags & FLAG_CPU(target.cpu)))
- {
- /* ignore this entry point */
- spec->nb_entry_points--;
- return 1;
- }
- if (data_only && !(odp->flags & FLAG_FORWARD))
- {
- error( "Only forwarded entry points are allowed in data-only mode\n" );
- goto error;
- }
- if (ordinal != -1)
- {
- if (!ordinal)
- {
- error( "Ordinal 0 is not valid\n" );
- goto error;
- }
- if (ordinal >= MAX_ORDINALS)
- {
- error( "Ordinal number %d too large\n", ordinal );
- goto error;
- }
- if (ordinal > spec->limit) spec->limit = ordinal;
- if (ordinal < spec->base) spec->base = ordinal;
- odp->ordinal = ordinal;
- }
- if (odp->type == TYPE_STDCALL && !(odp->flags & FLAG_PRIVATE))
- {
- if (!strcmp( odp->name, "DllRegisterServer" ) ||
- !strcmp( odp->name, "DllUnregisterServer" ) ||
- !strcmp( odp->name, "DllMain" ) ||
- !strcmp( odp->name, "DllGetClassObject" ) ||
- !strcmp( odp->name, "DllGetVersion" ) ||
- !strcmp( odp->name, "DllInstall" ) ||
- !strcmp( odp->name, "DllCanUnloadNow" ))
- {
- warning( "Function %s should be marked private\n", odp->name );
- if (strcmp( odp->name, odp->link_name ))
- warning( "Function %s should not use a different internal name (%s)\n",
- odp->name, odp->link_name );
- }
- }
- if (!strcmp( odp->name, "@" ) || odp->flags & (FLAG_NONAME | FLAG_ORDINAL))
- {
- if (ordinal == -1)
- {
- if (!strcmp( odp->name, "@" ))
- error( "Nameless function needs an explicit ordinal number\n" );
- else
- error( "Function imported by ordinal needs an explicit ordinal number\n" );
- goto error;
- }
- if (spec->type != SPEC_WIN32)
- {
- error( "Nameless functions not supported for Win16\n" );
- goto error;
- }
- if (!strcmp( odp->name, "@" ))
- {
- free( odp->name );
- odp->name = NULL;
- }
- else if (!(odp->flags & FLAG_ORDINAL)) /* -ordinal only affects the import library */
- {
- odp->export_name = odp->name;
- odp->name = NULL;
- }
- }
- return 1;
- error:
- spec->nb_entry_points--;
- free( odp->name );
- return 0;
- }
- static unsigned int apiset_hash_len( const char *str )
- {
- return strrchr( str, '-' ) - str;
- }
- static unsigned int apiset_hash( const char *str )
- {
- unsigned int ret = 0, len = apiset_hash_len( str );
- while (len--) ret = ret * apiset_hash_factor + *str++;
- return ret;
- }
- static unsigned int apiset_add_str( struct apiset *apiset, const char *str, unsigned int len )
- {
- char *ret;
- if (!apiset->strings || !(ret = strstr( apiset->strings, str )))
- {
- if (apiset->str_pos + len >= apiset->str_size)
- {
- apiset->str_size = max( apiset->str_size * 2, 1024 );
- apiset->strings = xrealloc( apiset->strings, apiset->str_size );
- }
- ret = apiset->strings + apiset->str_pos;
- memcpy( ret, str, len );
- ret[len] = 0;
- apiset->str_pos += len;
- }
- return ret - apiset->strings;
- }
- static void add_apiset( struct apiset *apiset, const char *api )
- {
- struct apiset_entry *entry;
- if (apiset->count == apiset->size)
- {
- apiset->size = max( apiset->size * 2, 64 );
- apiset->entries = xrealloc( apiset->entries, apiset->size * sizeof(*apiset->entries) );
- }
- entry = &apiset->entries[apiset->count++];
- entry->name_len = strlen( api );
- entry->name_off = apiset_add_str( apiset, api, entry->name_len );
- entry->hash = apiset_hash( api );
- entry->hash_len = apiset_hash_len( api );
- entry->val_count = 0;
- }
- static void add_apiset_value( struct apiset *apiset, const char *value )
- {
- struct apiset_entry *entry = &apiset->entries[apiset->count - 1];
- if (entry->val_count < ARRAY_SIZE(entry->values) - 1)
- {
- struct apiset_value *val = &entry->values[entry->val_count++];
- char *sep = strchr( value, ':' );
- if (sep)
- {
- val->name_len = sep - value;
- val->name_off = apiset_add_str( apiset, value, val->name_len );
- val->val_len = strlen( sep + 1 );
- val->val_off = apiset_add_str( apiset, sep + 1, val->val_len );
- }
- else
- {
- val->name_len = val->name_off = 0;
- val->val_len = strlen( value );
- val->val_off = apiset_add_str( apiset, value, val->val_len );
- }
- }
- else error( "Too many values for api '%.*s'\n", entry->name_len, apiset->strings + entry->name_off );
- }
- /*******************************************************************
- * parse_spec_apiset
- */
- static int parse_spec_apiset( DLLSPEC *spec )
- {
- struct apiset_entry *entry;
- const char *token;
- unsigned int i, hash;
- if (!data_only)
- {
- error( "Apiset definitions are only allowed in data-only mode\n" );
- return 0;
- }
- if (!(token = GetToken(0))) return 0;
- if (!strncmp( token, "api-", 4 ) && !strncmp( token, "ext-", 4 ))
- {
- error( "Unrecognized API set name '%s'\n", token );
- return 0;
- }
- hash = apiset_hash( token );
- for (i = 0, entry = spec->apiset.entries; i < spec->apiset.count; i++, entry++)
- {
- if (entry->name_len == strlen( token ) &&
- !strncmp( spec->apiset.strings + entry->name_off, token, entry->name_len ))
- {
- error( "Duplicate API set '%s'\n", token );
- return 0;
- }
- if (entry->hash == hash)
- {
- error( "Duplicate hash code '%.*s' and '%s'\n",
- entry->name_len, spec->apiset.strings + entry->name_off, token );
- return 0;
- }
- }
- add_apiset( &spec->apiset, token );
- if (!(token = GetToken(0)) || strcmp( token, "=" ))
- {
- error( "Syntax error near '%s'\n", token );
- return 0;
- }
- while ((token = GetToken(1))) add_apiset_value( &spec->apiset, token );
- return 1;
- }
- static int name_compare( const void *ptr1, const void *ptr2 )
- {
- const ORDDEF *odp1 = *(const ORDDEF * const *)ptr1;
- const ORDDEF *odp2 = *(const ORDDEF * const *)ptr2;
- const char *name1 = odp1->name ? odp1->name : odp1->export_name;
- const char *name2 = odp2->name ? odp2->name : odp2->export_name;
- return strcmp( name1, name2 );
- }
- /*******************************************************************
- * assign_names
- *
- * Build the name array and catch duplicates.
- */
- static void assign_names( DLLSPEC *spec )
- {
- int i, j, nb_exp_names = 0;
- ORDDEF **all_names;
- spec->nb_names = 0;
- for (i = 0; i < spec->nb_entry_points; i++)
- if (spec->entry_points[i].name) spec->nb_names++;
- else if (spec->entry_points[i].export_name) nb_exp_names++;
- if (!spec->nb_names && !nb_exp_names) return;
- /* check for duplicates */
- all_names = xmalloc( (spec->nb_names + nb_exp_names) * sizeof(all_names[0]) );
- for (i = j = 0; i < spec->nb_entry_points; i++)
- if (spec->entry_points[i].name || spec->entry_points[i].export_name)
- all_names[j++] = &spec->entry_points[i];
- qsort( all_names, j, sizeof(all_names[0]), name_compare );
- for (i = 0; i < j - 1; i++)
- {
- const char *name1 = all_names[i]->name ? all_names[i]->name : all_names[i]->export_name;
- const char *name2 = all_names[i+1]->name ? all_names[i+1]->name : all_names[i+1]->export_name;
- if (!strcmp( name1, name2 ) &&
- !((all_names[i]->flags ^ all_names[i+1]->flags) & FLAG_EXPORT32))
- {
- current_line = max( all_names[i]->lineno, all_names[i+1]->lineno );
- error( "'%s' redefined\n%s:%d: First defined here\n",
- name1, input_file_name,
- min( all_names[i]->lineno, all_names[i+1]->lineno ) );
- }
- }
- free( all_names );
- if (spec->nb_names)
- {
- spec->names = xmalloc( spec->nb_names * sizeof(spec->names[0]) );
- for (i = j = 0; i < spec->nb_entry_points; i++)
- if (spec->entry_points[i].name) spec->names[j++] = &spec->entry_points[i];
- /* sort the list of names */
- qsort( spec->names, spec->nb_names, sizeof(spec->names[0]), name_compare );
- for (i = 0; i < spec->nb_names; i++) spec->names[i]->hint = i;
- }
- }
- /*******************************************************************
- * assign_ordinals
- *
- * Build the ordinal array.
- */
- static void assign_ordinals( DLLSPEC *spec )
- {
- int i, count, ordinal;
- /* start assigning from base, or from 1 if no ordinal defined yet */
- spec->base = MAX_ORDINALS;
- spec->limit = 0;
- for (i = 0; i < spec->nb_entry_points; i++)
- {
- ordinal = spec->entry_points[i].ordinal;
- if (ordinal == -1) continue;
- if (ordinal > spec->limit) spec->limit = ordinal;
- if (ordinal < spec->base) spec->base = ordinal;
- }
- if (spec->base == MAX_ORDINALS) spec->base = 1;
- if (spec->limit < spec->base) spec->limit = spec->base;
- count = max( spec->limit + 1, spec->base + spec->nb_entry_points );
- spec->ordinals = xmalloc( count * sizeof(spec->ordinals[0]) );
- memset( spec->ordinals, 0, count * sizeof(spec->ordinals[0]) );
- /* fill in all explicitly specified ordinals */
- for (i = 0; i < spec->nb_entry_points; i++)
- {
- ordinal = spec->entry_points[i].ordinal;
- if (ordinal == -1) continue;
- if (spec->ordinals[ordinal])
- {
- current_line = max( spec->entry_points[i].lineno, spec->ordinals[ordinal]->lineno );
- error( "ordinal %d redefined\n%s:%d: First defined here\n",
- ordinal, input_file_name,
- min( spec->entry_points[i].lineno, spec->ordinals[ordinal]->lineno ) );
- }
- else spec->ordinals[ordinal] = &spec->entry_points[i];
- }
- /* now assign ordinals to the rest */
- for (i = 0, ordinal = spec->base; i < spec->nb_entry_points; i++)
- {
- if (spec->entry_points[i].ordinal != -1) continue;
- while (spec->ordinals[ordinal]) ordinal++;
- if (ordinal >= MAX_ORDINALS)
- {
- current_line = spec->entry_points[i].lineno;
- fatal_error( "Too many functions defined (max %d)\n", MAX_ORDINALS );
- }
- spec->entry_points[i].ordinal = ordinal;
- spec->ordinals[ordinal] = &spec->entry_points[i];
- }
- if (ordinal > spec->limit) spec->limit = ordinal;
- }
- /*******************************************************************
- * add_16bit_exports
- *
- * Add the necessary exports to the 32-bit counterpart of a 16-bit module.
- */
- void add_16bit_exports( DLLSPEC *spec32, DLLSPEC *spec16 )
- {
- int i;
- ORDDEF *odp;
- spec32->file_name = xstrdup( spec16->file_name );
- spec32->characteristics = IMAGE_FILE_DLL;
- spec32->init_func = xstrdup( "DllMain" );
- /* add an export for the NE module */
- odp = add_entry_point( spec32 );
- odp->type = TYPE_EXTERN;
- odp->flags = FLAG_PRIVATE;
- odp->name = xstrdup( "__wine_spec_dos_header" );
- odp->lineno = 0;
- odp->ordinal = 1;
- odp->link_name = xstrdup( ".L__wine_spec_dos_header" );
- if (spec16->main_module)
- {
- odp = add_entry_point( spec32 );
- odp->type = TYPE_EXTERN;
- odp->flags = FLAG_PRIVATE;
- odp->name = xstrdup( "__wine_spec_main_module" );
- odp->lineno = 0;
- odp->ordinal = 2;
- odp->link_name = xstrdup( ".L__wine_spec_main_module" );
- }
- /* add the explicit win32 exports */
- for (i = 1; i <= spec16->limit; i++)
- {
- ORDDEF *odp16 = spec16->ordinals[i];
- if (!odp16 || !odp16->name) continue;
- if (!(odp16->flags & FLAG_EXPORT32)) continue;
- odp = add_entry_point( spec32 );
- odp->flags = odp16->flags & ~FLAG_EXPORT32;
- odp->type = odp16->type;
- odp->name = xstrdup( odp16->name );
- odp->lineno = odp16->lineno;
- odp->ordinal = -1;
- odp->link_name = xstrdup( odp16->link_name );
- odp->u.func.nb_args = odp16->u.func.nb_args;
- if (odp->u.func.nb_args > 0) memcpy( odp->u.func.args, odp16->u.func.args,
- odp->u.func.nb_args * sizeof(odp->u.func.args[0]) );
- }
- assign_names( spec32 );
- assign_ordinals( spec32 );
- }
- /*******************************************************************
- * parse_spec_file
- *
- * Parse a .spec file.
- */
- int parse_spec_file( FILE *file, DLLSPEC *spec )
- {
- const char *token;
- input_file = file;
- current_line = 0;
- comment_chars = "#;";
- separator_chars = "()";
- while (get_next_line())
- {
- if (!(token = GetToken(1))) continue;
- if (strcmp(token, "@") == 0)
- {
- if (!parse_spec_ordinal( -1, spec )) continue;
- }
- else if (IsNumberString(token))
- {
- if (!parse_spec_ordinal( atoi(token), spec )) continue;
- }
- else if (strcmp(token, "apiset") == 0)
- {
- if (!parse_spec_apiset( spec )) continue;
- }
- else
- {
- error( "Expected ordinal declaration, got '%s'\n", token );
- continue;
- }
- if ((token = GetToken(1))) error( "Syntax error near '%s'\n", token );
- }
- current_line = 0; /* no longer parsing the input file */
- assign_names( spec );
- assign_ordinals( spec );
- return !nb_errors;
- }
- /*******************************************************************
- * parse_def_library
- *
- * Parse a LIBRARY declaration in a .def file.
- */
- static int parse_def_library( DLLSPEC *spec )
- {
- const char *token = GetToken(1);
- if (!token) return 1;
- if (strcmp( token, "BASE" ))
- {
- free( spec->file_name );
- spec->file_name = xstrdup( token );
- if (!(token = GetToken(1))) return 1;
- }
- if (strcmp( token, "BASE" ))
- {
- error( "Expected library name or BASE= declaration, got '%s'\n", token );
- return 0;
- }
- if (!(token = GetToken(0))) return 0;
- if (strcmp( token, "=" ))
- {
- error( "Expected '=' after BASE, got '%s'\n", token );
- return 0;
- }
- if (!(token = GetToken(0))) return 0;
- /* FIXME: do something with base address */
- return 1;
- }
- /*******************************************************************
- * parse_def_stack_heap_size
- *
- * Parse a STACKSIZE or HEAPSIZE declaration in a .def file.
- */
- static int parse_def_stack_heap_size( int is_stack, DLLSPEC *spec )
- {
- const char *token = GetToken(0);
- char *end;
- unsigned long size;
- if (!token) return 0;
- size = strtoul( token, &end, 0 );
- if (*end)
- {
- error( "Invalid number '%s'\n", token );
- return 0;
- }
- if (is_stack) spec->stack_size = size / 1024;
- else spec->heap_size = size / 1024;
- if (!(token = GetToken(1))) return 1;
- if (strcmp( token, "," ))
- {
- error( "Expected ',' after size, got '%s'\n", token );
- return 0;
- }
- if (!(token = GetToken(0))) return 0;
- /* FIXME: do something with reserve size */
- return 1;
- }
- /*******************************************************************
- * parse_def_export
- *
- * Parse an export declaration in a .def file.
- */
- static int parse_def_export( char *name, DLLSPEC *spec )
- {
- int i, args;
- const char *token = GetToken(1);
- ORDDEF *odp = add_entry_point( spec );
- odp->lineno = current_line;
- odp->ordinal = -1;
- odp->name = name;
- args = remove_stdcall_decoration( odp->name );
- if (args == -1)
- {
- odp->type = TYPE_CDECL;
- args = 0;
- }
- else
- {
- odp->type = TYPE_STDCALL;
- args /= get_ptr_size();
- if (args >= MAX_ARGUMENTS)
- {
- error( "Too many arguments in stdcall function '%s'\n", odp->name );
- return 0;
- }
- for (i = 0; i < args; i++) odp->u.func.args[i] = ARG_LONG;
- }
- odp->u.func.nb_args = args;
- /* check for optional internal name */
- if (token && !strcmp( token, "=" ))
- {
- if (!(token = GetToken(0))) goto error;
- odp->link_name = xstrdup( token );
- remove_stdcall_decoration( odp->link_name );
- token = GetToken(1);
- }
- else
- {
- odp->link_name = xstrdup( name );
- }
- /* check for optional ordinal */
- if (token && token[0] == '@')
- {
- int ordinal;
- if (!IsNumberString( token+1 ))
- {
- error( "Expected number after '@', got '%s'\n", token+1 );
- goto error;
- }
- ordinal = atoi( token+1 );
- if (!ordinal)
- {
- error( "Ordinal 0 is not valid\n" );
- goto error;
- }
- if (ordinal >= MAX_ORDINALS)
- {
- error( "Ordinal number %d too large\n", ordinal );
- goto error;
- }
- odp->ordinal = ordinal;
- token = GetToken(1);
- }
- /* check for other optional keywords */
- while (token)
- {
- if (!strcmp( token, "NONAME" ))
- {
- if (odp->ordinal == -1)
- {
- error( "NONAME requires an ordinal\n" );
- goto error;
- }
- odp->export_name = odp->name;
- odp->name = NULL;
- odp->flags |= FLAG_NONAME;
- }
- else if (!strcmp( token, "PRIVATE" ))
- {
- odp->flags |= FLAG_PRIVATE;
- }
- else if (!strcmp( token, "DATA" ))
- {
- odp->type = TYPE_EXTERN;
- }
- else
- {
- error( "Garbage text '%s' found at end of export declaration\n", token );
- goto error;
- }
- token = GetToken(1);
- }
- return 1;
- error:
- spec->nb_entry_points--;
- free( odp->name );
- return 0;
- }
- /*******************************************************************
- * parse_def_file
- *
- * Parse a .def file.
- */
- int parse_def_file( FILE *file, DLLSPEC *spec )
- {
- const char *token;
- int in_exports = 0;
- input_file = file;
- current_line = 0;
- comment_chars = ";";
- separator_chars = ",=";
- while (get_next_line())
- {
- if (!(token = GetToken(1))) continue;
- if (!strcmp( token, "LIBRARY" ) || !strcmp( token, "NAME" ))
- {
- if (!parse_def_library( spec )) continue;
- goto end_of_line;
- }
- else if (!strcmp( token, "STACKSIZE" ))
- {
- if (!parse_def_stack_heap_size( 1, spec )) continue;
- goto end_of_line;
- }
- else if (!strcmp( token, "HEAPSIZE" ))
- {
- if (!parse_def_stack_heap_size( 0, spec )) continue;
- goto end_of_line;
- }
- else if (!strcmp( token, "EXPORTS" ))
- {
- in_exports = 1;
- if (!(token = GetToken(1))) continue;
- }
- else if (!strcmp( token, "IMPORTS" ))
- {
- in_exports = 0;
- if (!(token = GetToken(1))) continue;
- }
- else if (!strcmp( token, "SECTIONS" ))
- {
- in_exports = 0;
- if (!(token = GetToken(1))) continue;
- }
- if (!in_exports) continue; /* ignore this line */
- if (!parse_def_export( xstrdup(token), spec )) continue;
- end_of_line:
- if ((token = GetToken(1))) error( "Syntax error near '%s'\n", token );
- }
- current_line = 0; /* no longer parsing the input file */
- assign_names( spec );
- assign_ordinals( spec );
- return !nb_errors;
- }
|