[10298] | 1 | /*
|
---|
| 2 | * Spec file parser
|
---|
| 3 | *
|
---|
| 4 | * Copyright 1993 Robert J. Amstadt
|
---|
| 5 | * Copyright 1995 Martin von Loewis
|
---|
| 6 | * Copyright 1995, 1996, 1997 Alexandre Julliard
|
---|
| 7 | * Copyright 1997 Eric Youngdale
|
---|
| 8 | * Copyright 1999 Ulrich Weigand
|
---|
| 9 | *
|
---|
| 10 | * This library is free software; you can redistribute it and/or
|
---|
| 11 | * modify it under the terms of the GNU Lesser General Public
|
---|
| 12 | * License as published by the Free Software Foundation; either
|
---|
| 13 | * version 2.1 of the License, or (at your option) any later version.
|
---|
| 14 | *
|
---|
| 15 | * This library is distributed in the hope that it will be useful,
|
---|
| 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 18 | * Lesser General Public License for more details.
|
---|
| 19 | *
|
---|
| 20 | * You should have received a copy of the GNU Lesser General Public
|
---|
| 21 | * License along with this library; if not, write to the Free Software
|
---|
| 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
---|
| 23 | */
|
---|
| 24 |
|
---|
| 25 | #include "config.h"
|
---|
| 26 | #include "wine/port.h"
|
---|
| 27 |
|
---|
| 28 | #include <assert.h>
|
---|
| 29 | #include <ctype.h>
|
---|
| 30 | #include <stdarg.h>
|
---|
| 31 | #include <stdio.h>
|
---|
| 32 | #include <stdlib.h>
|
---|
| 33 | #include <string.h>
|
---|
| 34 |
|
---|
| 35 | #include "windef.h"
|
---|
| 36 | #include "winbase.h"
|
---|
| 37 | #include "build.h"
|
---|
| 38 |
|
---|
| 39 | int current_line = 0;
|
---|
| 40 |
|
---|
| 41 | static char ParseBuffer[512];
|
---|
| 42 | static char TokenBuffer[512];
|
---|
| 43 | static char *ParseNext = ParseBuffer;
|
---|
| 44 | static FILE *input_file;
|
---|
| 45 |
|
---|
| 46 | static const char * const TypeNames[TYPE_NBTYPES] =
|
---|
| 47 | {
|
---|
| 48 | "variable", /* TYPE_VARIABLE */
|
---|
| 49 | "pascal", /* TYPE_PASCAL */
|
---|
| 50 | "equate", /* TYPE_ABS */
|
---|
| 51 | "stub", /* TYPE_STUB */
|
---|
| 52 | "stdcall", /* TYPE_STDCALL */
|
---|
| 53 | "cdecl", /* TYPE_CDECL */
|
---|
| 54 | "varargs", /* TYPE_VARARGS */
|
---|
| 55 | "extern" /* TYPE_EXTERN */
|
---|
| 56 | };
|
---|
| 57 |
|
---|
| 58 | static const char * const FlagNames[] =
|
---|
| 59 | {
|
---|
| 60 | "norelay", /* FLAG_NORELAY */
|
---|
| 61 | "noname", /* FLAG_NONAME */
|
---|
| 62 | "ret16", /* FLAG_RET16 */
|
---|
| 63 | "ret64", /* FLAG_RET64 */
|
---|
| 64 | "i386", /* FLAG_I386 */
|
---|
| 65 | "register", /* FLAG_REGISTER */
|
---|
| 66 | "interrupt", /* FLAG_INTERRUPT */
|
---|
| 67 | "private", /* FLAG_PRIVATE */
|
---|
| 68 | NULL
|
---|
| 69 | };
|
---|
| 70 |
|
---|
| 71 | static int IsNumberString(const char *s)
|
---|
| 72 | {
|
---|
| 73 | while (*s) if (!isdigit(*s++)) return 0;
|
---|
| 74 | return 1;
|
---|
| 75 | }
|
---|
| 76 |
|
---|
| 77 | inline static int is_token_separator( char ch )
|
---|
| 78 | {
|
---|
| 79 | return (ch == '(' || ch == ')' || ch == '-');
|
---|
| 80 | }
|
---|
| 81 |
|
---|
| 82 | /* get the next line from the input file, or return 0 if at eof */
|
---|
| 83 | static int get_next_line(void)
|
---|
| 84 | {
|
---|
| 85 | ParseNext = ParseBuffer;
|
---|
| 86 | current_line++;
|
---|
| 87 | return (fgets(ParseBuffer, sizeof(ParseBuffer), input_file) != NULL);
|
---|
| 88 | }
|
---|
| 89 |
|
---|
| 90 | static const char * GetToken( int allow_eol )
|
---|
| 91 | {
|
---|
| 92 | char *p = ParseNext;
|
---|
| 93 | char *token = TokenBuffer;
|
---|
| 94 |
|
---|
| 95 | for (;;)
|
---|
| 96 | {
|
---|
| 97 | /* remove initial white space */
|
---|
| 98 | p = ParseNext;
|
---|
| 99 | while (isspace(*p)) p++;
|
---|
| 100 |
|
---|
| 101 | if (*p == '\\' && p[1] == '\n') /* line continuation */
|
---|
| 102 | {
|
---|
| 103 | if (!get_next_line())
|
---|
| 104 | {
|
---|
| 105 | if (!allow_eol) error( "Unexpected end of file\n" );
|
---|
| 106 | return NULL;
|
---|
| 107 | }
|
---|
| 108 | }
|
---|
| 109 | else break;
|
---|
| 110 | }
|
---|
| 111 |
|
---|
| 112 | if ((*p == '\0') || (*p == '#'))
|
---|
| 113 | {
|
---|
| 114 | if (!allow_eol) error( "Declaration not terminated properly\n" );
|
---|
| 115 | return NULL;
|
---|
| 116 | }
|
---|
| 117 |
|
---|
| 118 | /*
|
---|
| 119 | * Find end of token.
|
---|
| 120 | */
|
---|
| 121 | if (is_token_separator(*p))
|
---|
| 122 | {
|
---|
| 123 | /* a separator is always a complete token */
|
---|
| 124 | *token++ = *p++;
|
---|
| 125 | }
|
---|
| 126 | else while (*p != '\0' && !is_token_separator(*p) && !isspace(*p))
|
---|
| 127 | {
|
---|
| 128 | if (*p == '\\') p++;
|
---|
| 129 | if (*p) *token++ = *p++;
|
---|
| 130 | }
|
---|
| 131 | *token = '\0';
|
---|
| 132 | ParseNext = p;
|
---|
| 133 | return TokenBuffer;
|
---|
| 134 | }
|
---|
| 135 |
|
---|
| 136 |
|
---|
| 137 | /*******************************************************************
|
---|
| 138 | * ParseVariable
|
---|
| 139 | *
|
---|
| 140 | * Parse a variable definition.
|
---|
| 141 | */
|
---|
| 142 | static int ParseVariable( ORDDEF *odp )
|
---|
| 143 | {
|
---|
| 144 | char *endptr;
|
---|
| 145 | int *value_array;
|
---|
| 146 | int n_values;
|
---|
| 147 | int value_array_size;
|
---|
| 148 | const char *token;
|
---|
| 149 |
|
---|
| 150 | if (SpecType == SPEC_WIN32)
|
---|
| 151 | {
|
---|
| 152 | error( "'variable' not supported in Win32, use 'extern' instead\n" );
|
---|
| 153 | return 0;
|
---|
| 154 | }
|
---|
| 155 |
|
---|
| 156 | if (!(token = GetToken(0))) return 0;
|
---|
| 157 | if (*token != '(')
|
---|
| 158 | {
|
---|
| 159 | error( "Expected '(' got '%s'\n", token );
|
---|
| 160 | return 0;
|
---|
| 161 | }
|
---|
| 162 |
|
---|
| 163 | n_values = 0;
|
---|
| 164 | value_array_size = 25;
|
---|
| 165 | value_array = xmalloc(sizeof(*value_array) * value_array_size);
|
---|
| 166 |
|
---|
| 167 | for (;;)
|
---|
| 168 | {
|
---|
| 169 | if (!(token = GetToken(0)))
|
---|
| 170 | {
|
---|
| 171 | free( value_array );
|
---|
| 172 | return 0;
|
---|
| 173 | }
|
---|
| 174 | if (*token == ')')
|
---|
| 175 | break;
|
---|
| 176 |
|
---|
| 177 | value_array[n_values++] = strtol(token, &endptr, 0);
|
---|
| 178 | if (n_values == value_array_size)
|
---|
| 179 | {
|
---|
| 180 | value_array_size += 25;
|
---|
| 181 | value_array = xrealloc(value_array,
|
---|
| 182 | sizeof(*value_array) * value_array_size);
|
---|
| 183 | }
|
---|
| 184 |
|
---|
| 185 | if (endptr == NULL || *endptr != '\0')
|
---|
| 186 | {
|
---|
| 187 | error( "Expected number value, got '%s'\n", token );
|
---|
| 188 | free( value_array );
|
---|
| 189 | return 0;
|
---|
| 190 | }
|
---|
| 191 | }
|
---|
| 192 |
|
---|
| 193 | odp->u.var.n_values = n_values;
|
---|
| 194 | odp->u.var.values = xrealloc(value_array, sizeof(*value_array) * n_values);
|
---|
| 195 | return 1;
|
---|
| 196 | }
|
---|
| 197 |
|
---|
| 198 |
|
---|
| 199 | /*******************************************************************
|
---|
| 200 | * ParseExportFunction
|
---|
| 201 | *
|
---|
| 202 | * Parse a function definition.
|
---|
| 203 | */
|
---|
| 204 | static int ParseExportFunction( ORDDEF *odp )
|
---|
| 205 | {
|
---|
| 206 | const char *token;
|
---|
| 207 | unsigned int i;
|
---|
| 208 |
|
---|
| 209 | switch(SpecType)
|
---|
| 210 | {
|
---|
| 211 | case SPEC_WIN16:
|
---|
| 212 | if (odp->type == TYPE_STDCALL)
|
---|
| 213 | {
|
---|
| 214 | error( "'stdcall' not supported for Win16\n" );
|
---|
| 215 | return 0;
|
---|
| 216 | }
|
---|
| 217 | break;
|
---|
| 218 | case SPEC_WIN32:
|
---|
| 219 | if (odp->type == TYPE_PASCAL)
|
---|
| 220 | {
|
---|
| 221 | error( "'pascal' not supported for Win32\n" );
|
---|
| 222 | return 0;
|
---|
| 223 | }
|
---|
| 224 | if (odp->flags & FLAG_INTERRUPT)
|
---|
| 225 | {
|
---|
| 226 | error( "'interrupt' not supported for Win32\n" );
|
---|
| 227 | return 0;
|
---|
| 228 | }
|
---|
| 229 | break;
|
---|
| 230 | default:
|
---|
| 231 | break;
|
---|
| 232 | }
|
---|
| 233 |
|
---|
| 234 | if (!(token = GetToken(0))) return 0;
|
---|
| 235 | if (*token != '(')
|
---|
| 236 | {
|
---|
| 237 | error( "Expected '(' got '%s'\n", token );
|
---|
| 238 | return 0;
|
---|
| 239 | }
|
---|
| 240 |
|
---|
| 241 | for (i = 0; i < sizeof(odp->u.func.arg_types); i++)
|
---|
| 242 | {
|
---|
| 243 | if (!(token = GetToken(0))) return 0;
|
---|
| 244 | if (*token == ')')
|
---|
| 245 | break;
|
---|
| 246 |
|
---|
| 247 | if (!strcmp(token, "word"))
|
---|
| 248 | odp->u.func.arg_types[i] = 'w';
|
---|
| 249 | else if (!strcmp(token, "s_word"))
|
---|
| 250 | odp->u.func.arg_types[i] = 's';
|
---|
| 251 | else if (!strcmp(token, "long") || !strcmp(token, "segptr"))
|
---|
| 252 | odp->u.func.arg_types[i] = 'l';
|
---|
| 253 | else if (!strcmp(token, "ptr"))
|
---|
| 254 | odp->u.func.arg_types[i] = 'p';
|
---|
| 255 | else if (!strcmp(token, "str"))
|
---|
| 256 | odp->u.func.arg_types[i] = 't';
|
---|
| 257 | else if (!strcmp(token, "wstr"))
|
---|
| 258 | odp->u.func.arg_types[i] = 'W';
|
---|
| 259 | else if (!strcmp(token, "segstr"))
|
---|
| 260 | odp->u.func.arg_types[i] = 'T';
|
---|
| 261 | else if (!strcmp(token, "double"))
|
---|
| 262 | {
|
---|
| 263 | odp->u.func.arg_types[i++] = 'l';
|
---|
| 264 | if (i < sizeof(odp->u.func.arg_types)) odp->u.func.arg_types[i] = 'l';
|
---|
| 265 | }
|
---|
| 266 | else
|
---|
| 267 | {
|
---|
| 268 | error( "Unknown argument type '%s'\n", token );
|
---|
| 269 | return 0;
|
---|
| 270 | }
|
---|
| 271 |
|
---|
| 272 | if (SpecType == SPEC_WIN32)
|
---|
| 273 | {
|
---|
| 274 | if (strcmp(token, "long") &&
|
---|
| 275 | strcmp(token, "ptr") &&
|
---|
| 276 | strcmp(token, "str") &&
|
---|
| 277 | strcmp(token, "wstr") &&
|
---|
| 278 | strcmp(token, "double"))
|
---|
| 279 | {
|
---|
| 280 | error( "Type '%s' not supported for Win32\n", token );
|
---|
| 281 | return 0;
|
---|
| 282 | }
|
---|
| 283 | }
|
---|
| 284 | }
|
---|
| 285 | if ((*token != ')') || (i >= sizeof(odp->u.func.arg_types)))
|
---|
| 286 | {
|
---|
| 287 | error( "Too many arguments\n" );
|
---|
| 288 | return 0;
|
---|
| 289 | }
|
---|
| 290 |
|
---|
| 291 | odp->u.func.arg_types[i] = '\0';
|
---|
| 292 | if (odp->type == TYPE_VARARGS)
|
---|
| 293 | odp->flags |= FLAG_NORELAY; /* no relay debug possible for varags entry point */
|
---|
| 294 |
|
---|
| 295 | if (!(token = GetToken(1)))
|
---|
| 296 | {
|
---|
| 297 | if (!strcmp( odp->name, "@" ))
|
---|
| 298 | {
|
---|
| 299 | error( "Missing handler name for anonymous function\n" );
|
---|
| 300 | return 0;
|
---|
| 301 | }
|
---|
| 302 | odp->link_name = xstrdup( odp->name );
|
---|
| 303 | }
|
---|
| 304 | else
|
---|
| 305 | {
|
---|
| 306 | odp->link_name = xstrdup( token );
|
---|
| 307 | if (strchr( odp->link_name, '.' ))
|
---|
| 308 | {
|
---|
| 309 | if (SpecType == SPEC_WIN16)
|
---|
| 310 | {
|
---|
| 311 | error( "Forwarded functions not supported for Win16\n" );
|
---|
| 312 | return 0;
|
---|
| 313 | }
|
---|
| 314 | odp->flags |= FLAG_FORWARD;
|
---|
| 315 | }
|
---|
| 316 | }
|
---|
| 317 | return 1;
|
---|
| 318 | }
|
---|
| 319 |
|
---|
| 320 |
|
---|
| 321 | /*******************************************************************
|
---|
| 322 | * ParseEquate
|
---|
| 323 | *
|
---|
| 324 | * Parse an 'equate' definition.
|
---|
| 325 | */
|
---|
| 326 | static int ParseEquate( ORDDEF *odp )
|
---|
| 327 | {
|
---|
| 328 | char *endptr;
|
---|
| 329 | int value;
|
---|
| 330 | const char *token;
|
---|
| 331 |
|
---|
| 332 | if (SpecType == SPEC_WIN32)
|
---|
| 333 | {
|
---|
| 334 | error( "'equate' not supported for Win32\n" );
|
---|
| 335 | return 0;
|
---|
| 336 | }
|
---|
| 337 | if (!(token = GetToken(0))) return 0;
|
---|
| 338 | value = strtol(token, &endptr, 0);
|
---|
| 339 | if (endptr == NULL || *endptr != '\0')
|
---|
| 340 | {
|
---|
| 341 | error( "Expected number value, got '%s'\n", token );
|
---|
| 342 | return 0;
|
---|
| 343 | }
|
---|
| 344 | odp->u.abs.value = value;
|
---|
| 345 | return 1;
|
---|
| 346 | }
|
---|
| 347 |
|
---|
| 348 |
|
---|
| 349 | /*******************************************************************
|
---|
| 350 | * ParseStub
|
---|
| 351 | *
|
---|
| 352 | * Parse a 'stub' definition.
|
---|
| 353 | */
|
---|
| 354 | static int ParseStub( ORDDEF *odp )
|
---|
| 355 | {
|
---|
| 356 | odp->u.func.arg_types[0] = '\0';
|
---|
| 357 | odp->link_name = xstrdup("");
|
---|
| 358 | return 1;
|
---|
| 359 | }
|
---|
| 360 |
|
---|
| 361 |
|
---|
| 362 | /*******************************************************************
|
---|
| 363 | * ParseExtern
|
---|
| 364 | *
|
---|
| 365 | * Parse an 'extern' definition.
|
---|
| 366 | */
|
---|
| 367 | static int ParseExtern( ORDDEF *odp )
|
---|
| 368 | {
|
---|
| 369 | const char *token;
|
---|
| 370 |
|
---|
| 371 | if (SpecType == SPEC_WIN16)
|
---|
| 372 | {
|
---|
| 373 | error( "'extern' not supported for Win16, use 'variable' instead\n" );
|
---|
| 374 | return 0;
|
---|
| 375 | }
|
---|
| 376 | if (!(token = GetToken(1)))
|
---|
| 377 | {
|
---|
| 378 | if (!strcmp( odp->name, "@" ))
|
---|
| 379 | {
|
---|
| 380 | error( "Missing handler name for anonymous extern\n" );
|
---|
| 381 | return 0;
|
---|
| 382 | }
|
---|
| 383 | odp->link_name = xstrdup( odp->name );
|
---|
| 384 | }
|
---|
| 385 | else
|
---|
| 386 | {
|
---|
| 387 | odp->link_name = xstrdup( token );
|
---|
| 388 | if (strchr( odp->link_name, '.' )) odp->flags |= FLAG_FORWARD;
|
---|
| 389 | }
|
---|
| 390 | return 1;
|
---|
| 391 | }
|
---|
| 392 |
|
---|
| 393 |
|
---|
| 394 | /*******************************************************************
|
---|
| 395 | * ParseFlags
|
---|
| 396 | *
|
---|
| 397 | * Parse the optional flags for an entry point
|
---|
| 398 | */
|
---|
| 399 | static const char *ParseFlags( ORDDEF *odp )
|
---|
| 400 | {
|
---|
| 401 | unsigned int i;
|
---|
| 402 | const char *token;
|
---|
| 403 |
|
---|
| 404 | do
|
---|
| 405 | {
|
---|
| 406 | if (!(token = GetToken(0))) break;
|
---|
| 407 | for (i = 0; FlagNames[i]; i++)
|
---|
| 408 | if (!strcmp( FlagNames[i], token )) break;
|
---|
| 409 | if (!FlagNames[i])
|
---|
| 410 | {
|
---|
| 411 | error( "Unknown flag '%s'\n", token );
|
---|
| 412 | return NULL;
|
---|
| 413 | }
|
---|
| 414 | odp->flags |= 1 << i;
|
---|
| 415 | token = GetToken(0);
|
---|
| 416 | } while (token && *token == '-');
|
---|
| 417 |
|
---|
| 418 | return token;
|
---|
| 419 | }
|
---|
| 420 |
|
---|
| 421 | /*******************************************************************
|
---|
| 422 | * fix_export_name
|
---|
| 423 | *
|
---|
| 424 | * Fix an exported function name by removing a possible @xx suffix
|
---|
| 425 | */
|
---|
| 426 | static void fix_export_name( char *name )
|
---|
| 427 | {
|
---|
| 428 | char *p, *end = strrchr( name, '@' );
|
---|
| 429 | if (!end || !end[1] || end == name) return;
|
---|
| 430 | /* make sure all the rest is digits */
|
---|
| 431 | for (p = end + 1; *p; p++) if (!isdigit(*p)) return;
|
---|
| 432 | *end = 0;
|
---|
| 433 | }
|
---|
| 434 |
|
---|
| 435 | /*******************************************************************
|
---|
| 436 | * ParseOrdinal
|
---|
| 437 | *
|
---|
| 438 | * Parse an ordinal definition.
|
---|
| 439 | */
|
---|
| 440 | static int ParseOrdinal(char *token, int ordinal)
|
---|
| 441 | {
|
---|
| 442 | int len, fNameExport = FALSE;
|
---|
| 443 | ORDDEF *odp = xmalloc( sizeof(*odp) );
|
---|
| 444 | memset( odp, 0, sizeof(*odp) );
|
---|
| 445 | EntryPoints[nb_entry_points++] = odp;
|
---|
| 446 |
|
---|
| 447 | odp->type = TYPE_STDCALL;
|
---|
| 448 |
|
---|
| 449 | if (strstr(ParseNext, "NONAME")) {
|
---|
| 450 | odp->flags = FLAG_NONAME;
|
---|
| 451 | if(token[0] == '\"') {
|
---|
| 452 | int len = strlen(token+1);
|
---|
| 453 | token++;
|
---|
| 454 | if(token[len-1] == '\"') token[len-1] = 0;
|
---|
| 455 | }
|
---|
| 456 |
|
---|
| 457 | odp->link_name = xstrdup( token );
|
---|
| 458 | len = strlen(odp->link_name);
|
---|
| 459 | if(odp->link_name[len-1] == '=') {
|
---|
| 460 | odp->link_name[len-1] = 0;
|
---|
| 461 | fNameExport = TRUE;
|
---|
| 462 | }
|
---|
| 463 | if(!fNameExport) token = GetToken(1);
|
---|
| 464 |
|
---|
| 465 | if(fNameExport || (token && *token == '=')) {
|
---|
| 466 | token = GetToken(1);
|
---|
| 467 | if(token && token[0] == '\"') {
|
---|
| 468 | int len = strlen(token+1);
|
---|
| 469 | token++;
|
---|
| 470 | if(token[len-1] == '\"') token[len-1] = 0;
|
---|
| 471 | }
|
---|
| 472 | if(token) odp->link_name = xstrdup(token);
|
---|
| 473 | }
|
---|
| 474 | }
|
---|
| 475 | else
|
---|
| 476 | {
|
---|
| 477 | if(token[0] == '\"') {
|
---|
| 478 | int len = strlen(token+1);
|
---|
| 479 | token++;
|
---|
| 480 | if(token[len-1] == '\"') token[len-1] = 0;
|
---|
| 481 | }
|
---|
| 482 | odp->name = xstrdup( token );
|
---|
| 483 | len = strlen(odp->name);
|
---|
| 484 | if(odp->name[len-1] == '=') {
|
---|
| 485 | odp->name[len-1] = 0;
|
---|
| 486 | fNameExport = TRUE;
|
---|
| 487 | }
|
---|
| 488 | if(!fNameExport) token = GetToken(1);
|
---|
| 489 |
|
---|
| 490 | if(fNameExport || (token && *token == '=')) {
|
---|
| 491 | token = GetToken(1);
|
---|
| 492 | if(token && token[0] == '\"') {
|
---|
| 493 | int len = strlen(token+1);
|
---|
| 494 | token++;
|
---|
| 495 | if(token[len-1] == '\"') token[len-1] = 0;
|
---|
| 496 | }
|
---|
| 497 | if(token) odp->link_name = xstrdup(token);
|
---|
| 498 | }
|
---|
| 499 | else odp->link_name = odp->name;
|
---|
| 500 |
|
---|
| 501 | fix_export_name( odp->name );
|
---|
| 502 | }
|
---|
| 503 | odp->lineno = current_line;
|
---|
| 504 | odp->ordinal = ordinal;
|
---|
| 505 |
|
---|
| 506 | if (!ordinal)
|
---|
| 507 | {
|
---|
| 508 | error( "Ordinal 0 is not valid\n" );
|
---|
| 509 | goto error;
|
---|
| 510 | }
|
---|
| 511 | if (ordinal >= MAX_ORDINALS)
|
---|
| 512 | {
|
---|
| 513 | error( "Ordinal number %d too large\n", ordinal );
|
---|
| 514 | goto error;
|
---|
| 515 | }
|
---|
| 516 | if (ordinal > Limit) Limit = ordinal;
|
---|
| 517 | if (ordinal < Base) Base = ordinal;
|
---|
| 518 | odp->ordinal = ordinal;
|
---|
| 519 | if (Ordinals[ordinal])
|
---|
| 520 | {
|
---|
| 521 | error( "Duplicate ordinal %d\n", ordinal );
|
---|
| 522 | goto error;
|
---|
| 523 | }
|
---|
| 524 | Ordinals[ordinal] = odp;
|
---|
| 525 |
|
---|
| 526 |
|
---|
| 527 | if (odp->flags & FLAG_NONAME)
|
---|
| 528 | {
|
---|
| 529 | if (ordinal == -1)
|
---|
| 530 | {
|
---|
| 531 | error( "Nameless function needs an explicit ordinal number\n" );
|
---|
| 532 | goto error;
|
---|
| 533 | }
|
---|
| 534 | if (SpecType != SPEC_WIN32)
|
---|
| 535 | {
|
---|
| 536 | error( "Nameless functions not supported for Win16\n" );
|
---|
| 537 | goto error;
|
---|
| 538 | }
|
---|
| 539 | odp->name = NULL;
|
---|
| 540 | }
|
---|
| 541 | else Names[nb_names++] = odp;
|
---|
| 542 | return 1;
|
---|
| 543 |
|
---|
| 544 | error:
|
---|
| 545 | EntryPoints[--nb_entry_points] = NULL;
|
---|
| 546 | free( odp->name );
|
---|
| 547 | free( odp );
|
---|
| 548 | return 0;
|
---|
| 549 | }
|
---|
| 550 |
|
---|
| 551 |
|
---|
| 552 | static int name_compare( const void *name1, const void *name2 )
|
---|
| 553 | {
|
---|
| 554 | ORDDEF *odp1 = *(ORDDEF **)name1;
|
---|
| 555 | ORDDEF *odp2 = *(ORDDEF **)name2;
|
---|
| 556 | return strcmp( odp1->name, odp2->name );
|
---|
| 557 | }
|
---|
| 558 |
|
---|
| 559 | /*******************************************************************
|
---|
| 560 | * sort_names
|
---|
| 561 | *
|
---|
| 562 | * Sort the name array and catch duplicates.
|
---|
| 563 | */
|
---|
| 564 | static void sort_names(void)
|
---|
| 565 | {
|
---|
| 566 | int i;
|
---|
| 567 |
|
---|
| 568 | if (!nb_names) return;
|
---|
| 569 |
|
---|
| 570 | /* sort the list of names */
|
---|
| 571 | qsort( Names, nb_names, sizeof(Names[0]), name_compare );
|
---|
| 572 |
|
---|
| 573 | /* check for duplicate names */
|
---|
| 574 | for (i = 0; i < nb_names - 1; i++)
|
---|
| 575 | {
|
---|
| 576 | if (!strcmp( Names[i]->name, Names[i+1]->name ))
|
---|
| 577 | {
|
---|
| 578 | current_line = max( Names[i]->lineno, Names[i+1]->lineno );
|
---|
| 579 | error( "'%s' redefined\n%s:%d: First defined here\n",
|
---|
| 580 | Names[i]->name, input_file_name,
|
---|
| 581 | min( Names[i]->lineno, Names[i+1]->lineno ) );
|
---|
| 582 | }
|
---|
| 583 | }
|
---|
| 584 | }
|
---|
| 585 |
|
---|
| 586 |
|
---|
| 587 | /*******************************************************************
|
---|
| 588 | * ParseTopLevel
|
---|
| 589 | *
|
---|
| 590 | * Parse a spec file.
|
---|
| 591 | */
|
---|
| 592 | char hextab[]="0123456789ABCDEF";
|
---|
| 593 |
|
---|
| 594 | int ParseTopLevel( FILE *file )
|
---|
| 595 | {
|
---|
| 596 | const char *token, *ordinal, *tmp;
|
---|
| 597 | int ord, i, j, val, k;
|
---|
| 598 |
|
---|
| 599 | input_file = file;
|
---|
| 600 | current_line = 0;
|
---|
| 601 |
|
---|
| 602 | while (get_next_line()) {
|
---|
| 603 | if (!(token = GetToken(1))) continue;
|
---|
| 604 | if(strstr(token, "EXPORT")) break;
|
---|
| 605 | }
|
---|
| 606 |
|
---|
| 607 | while (get_next_line())
|
---|
| 608 | {
|
---|
| 609 | if (!(token = GetToken(1))) continue;
|
---|
| 610 | if (token[0] == ';') {
|
---|
| 611 | if (!(token = GetToken(1))) continue;
|
---|
| 612 | if(!strcmp(token, "ENDOFEXPORTS")) break; //end of export section
|
---|
| 613 | continue; //comment
|
---|
| 614 | }
|
---|
| 615 |
|
---|
| 616 | ordinal = strstr(ParseNext, "@");
|
---|
| 617 | if(ordinal == NULL) continue;
|
---|
| 618 | ordinal++;
|
---|
| 619 | tmp = strstr(ordinal, "@");
|
---|
| 620 | if(tmp && (tmp[1] >= '0' && tmp[1] <= '9')) ordinal = tmp+1;
|
---|
| 621 |
|
---|
| 622 | while(*ordinal == ' ') ordinal++;
|
---|
| 623 |
|
---|
| 624 | strupr(ordinal);
|
---|
| 625 |
|
---|
| 626 | if(ordinal[0] == '0' && ordinal[1] == 'X')
|
---|
| 627 | {//hex ordinal
|
---|
| 628 | int len = strlen(ordinal)-2;
|
---|
| 629 |
|
---|
| 630 | ordinal = ordinal+2;
|
---|
| 631 | ord = 0;
|
---|
| 632 | if(ordinal[len-1] == '\n') len -= 1;
|
---|
| 633 |
|
---|
| 634 | for(i=0;i<len;i++) {
|
---|
| 635 | for(j=0;j<16;j++) {
|
---|
| 636 | if(hextab[j] == ordinal[i]) break;
|
---|
| 637 | }
|
---|
| 638 | if(j==16) {
|
---|
| 639 | printf("invalid hex number %s\n", ordinal);
|
---|
| 640 | exit(666);
|
---|
| 641 | }
|
---|
| 642 | val = 1;
|
---|
| 643 | for(k=0;k<len-i-1;k++) {
|
---|
| 644 | val *= 16;
|
---|
| 645 | }
|
---|
| 646 | ord += j*val;
|
---|
| 647 | }
|
---|
| 648 | }
|
---|
| 649 | else ord = atoi(ordinal);
|
---|
| 650 |
|
---|
| 651 | if (!ParseOrdinal( token, ord )) continue;
|
---|
| 652 | }
|
---|
| 653 |
|
---|
| 654 | current_line = 0; /* no longer parsing the input file */
|
---|
| 655 | sort_names();
|
---|
| 656 | return !nb_errors;
|
---|
| 657 | }
|
---|
| 658 |
|
---|
| 659 |
|
---|
| 660 | /*******************************************************************
|
---|
| 661 | * add_debug_channel
|
---|
| 662 | */
|
---|
| 663 | static void add_debug_channel( const char *name )
|
---|
| 664 | {
|
---|
| 665 | int i;
|
---|
| 666 |
|
---|
| 667 | for (i = 0; i < nb_debug_channels; i++)
|
---|
| 668 | if (!strcmp( debug_channels[i], name )) return;
|
---|
| 669 |
|
---|
| 670 | debug_channels = xrealloc( debug_channels, (nb_debug_channels + 1) * sizeof(*debug_channels));
|
---|
| 671 | debug_channels[nb_debug_channels++] = xstrdup(name);
|
---|
| 672 | }
|
---|
| 673 |
|
---|
| 674 |
|
---|
| 675 | /*******************************************************************
|
---|
| 676 | * parse_debug_channels
|
---|
| 677 | *
|
---|
| 678 | * Parse a source file and extract the debug channel definitions.
|
---|
| 679 | */
|
---|
| 680 | int parse_debug_channels( const char *srcdir, const char *filename )
|
---|
| 681 | {
|
---|
| 682 | FILE *file;
|
---|
| 683 | int eol_seen = 1;
|
---|
| 684 |
|
---|
| 685 | file = open_input_file( srcdir, filename );
|
---|
| 686 | while (fgets( ParseBuffer, sizeof(ParseBuffer), file ))
|
---|
| 687 | {
|
---|
| 688 | char *channel, *end, *p = ParseBuffer;
|
---|
| 689 |
|
---|
| 690 | p = ParseBuffer + strlen(ParseBuffer) - 1;
|
---|
| 691 | if (!eol_seen) /* continuation line */
|
---|
| 692 | {
|
---|
| 693 | eol_seen = (*p == '\n');
|
---|
| 694 | continue;
|
---|
| 695 | }
|
---|
| 696 | if ((eol_seen = (*p == '\n'))) *p = 0;
|
---|
| 697 |
|
---|
| 698 | p = ParseBuffer;
|
---|
| 699 | while (isspace(*p)) p++;
|
---|
| 700 | if (!memcmp( p, "WINE_DECLARE_DEBUG_CHANNEL", 26 ) ||
|
---|
| 701 | !memcmp( p, "WINE_DEFAULT_DEBUG_CHANNEL", 26 ))
|
---|
| 702 | {
|
---|
| 703 | p += 26;
|
---|
| 704 | while (isspace(*p)) p++;
|
---|
| 705 | if (*p != '(')
|
---|
| 706 | {
|
---|
| 707 | error( "invalid debug channel specification '%s'\n", ParseBuffer );
|
---|
| 708 | goto next;
|
---|
| 709 | }
|
---|
| 710 | p++;
|
---|
| 711 | while (isspace(*p)) p++;
|
---|
| 712 | if (!isalpha(*p))
|
---|
| 713 | {
|
---|
| 714 | error( "invalid debug channel specification '%s'\n", ParseBuffer );
|
---|
| 715 | goto next;
|
---|
| 716 | }
|
---|
| 717 | channel = p;
|
---|
| 718 | while (isalnum(*p) || *p == '_') p++;
|
---|
| 719 | end = p;
|
---|
| 720 | while (isspace(*p)) p++;
|
---|
| 721 | if (*p != ')')
|
---|
| 722 | {
|
---|
| 723 | error( "invalid debug channel specification '%s'\n", ParseBuffer );
|
---|
| 724 | goto next;
|
---|
| 725 | }
|
---|
| 726 | *end = 0;
|
---|
| 727 | add_debug_channel( channel );
|
---|
| 728 | }
|
---|
| 729 | next:
|
---|
| 730 | current_line++;
|
---|
| 731 | }
|
---|
| 732 | close_input_file( file );
|
---|
| 733 | return !nb_errors;
|
---|
| 734 | }
|
---|