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
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.
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.
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
26 #include "wine/port.h"
39 static char ParseBuffer[512];
40 static char TokenBuffer[512];
41 static char *ParseNext = ParseBuffer;
42 static FILE *input_file;
44 static const char * const TypeNames[TYPE_NBTYPES] =
46 "variable", /* TYPE_VARIABLE */
47 "pascal16", /* TYPE_PASCAL_16 */
48 "pascal", /* TYPE_PASCAL */
49 "equate", /* TYPE_ABS */
50 "stub", /* TYPE_STUB */
51 "stdcall", /* TYPE_STDCALL */
52 "cdecl", /* TYPE_CDECL */
53 "varargs", /* TYPE_VARARGS */
54 "extern" /* TYPE_EXTERN */
57 static const char * const FlagNames[] =
59 "norelay", /* FLAG_NORELAY */
60 "noname", /* FLAG_NONAME */
61 "ret64", /* FLAG_RET64 */
62 "i386", /* FLAG_I386 */
63 "register", /* FLAG_REGISTER */
64 "interrupt", /* FLAG_INTERRUPT */
68 static int IsNumberString(const char *s)
70 while (*s) if (!isdigit(*s++)) return 0;
74 inline static int is_token_separator( char ch )
76 return (ch == '(' || ch == ')' || ch == '-');
79 static const char * GetTokenInLine(void)
82 char *token = TokenBuffer;
85 * Remove initial white space.
87 while (isspace(*p)) p++;
89 if ((*p == '\0') || (*p == '#')) return NULL;
94 if (is_token_separator(*p))
96 /* a separator is always a complete token */
99 else while (*p != '\0' && !is_token_separator(*p) && !isspace(*p))
102 if (*p) *token++ = *p++;
109 static const char * GetToken( int allow_eof )
113 while ((token = GetTokenInLine()) == NULL)
115 ParseNext = ParseBuffer;
117 if (fgets(ParseBuffer, sizeof(ParseBuffer), input_file) == NULL)
119 if (!allow_eof) fatal_error( "Unexpected end of file\n" );
127 /*******************************************************************
130 * Parse a variable definition.
132 static void ParseVariable( ORDDEF *odp )
137 int value_array_size;
140 if (SpecType == SPEC_WIN32)
141 fatal_error( "'variable' not supported in Win32, use 'extern' instead\n" );
144 if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token );
147 value_array_size = 25;
148 value_array = xmalloc(sizeof(*value_array) * value_array_size);
156 value_array[n_values++] = strtol(token, &endptr, 0);
157 if (n_values == value_array_size)
159 value_array_size += 25;
160 value_array = xrealloc(value_array,
161 sizeof(*value_array) * value_array_size);
164 if (endptr == NULL || *endptr != '\0')
165 fatal_error( "Expected number value, got '%s'\n", token );
168 odp->u.var.n_values = n_values;
169 odp->u.var.values = xrealloc(value_array, sizeof(*value_array) * n_values);
173 /*******************************************************************
174 * ParseExportFunction
176 * Parse a function definition.
178 static void ParseExportFunction( ORDDEF *odp )
186 if (odp->type == TYPE_STDCALL)
187 fatal_error( "'stdcall' not supported for Win16\n" );
188 if (odp->type == TYPE_VARARGS)
189 fatal_error( "'varargs' not supported for Win16\n" );
192 if ((odp->type == TYPE_PASCAL) || (odp->type == TYPE_PASCAL_16))
193 fatal_error( "'pascal' not supported for Win32\n" );
194 if (odp->flags & FLAG_INTERRUPT)
195 fatal_error( "'interrupt' not supported for Win32\n" );
202 if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token );
204 for (i = 0; i < sizeof(odp->u.func.arg_types); i++)
210 if (!strcmp(token, "word"))
211 odp->u.func.arg_types[i] = 'w';
212 else if (!strcmp(token, "s_word"))
213 odp->u.func.arg_types[i] = 's';
214 else if (!strcmp(token, "long") || !strcmp(token, "segptr"))
215 odp->u.func.arg_types[i] = 'l';
216 else if (!strcmp(token, "ptr"))
217 odp->u.func.arg_types[i] = 'p';
218 else if (!strcmp(token, "str"))
219 odp->u.func.arg_types[i] = 't';
220 else if (!strcmp(token, "wstr"))
221 odp->u.func.arg_types[i] = 'W';
222 else if (!strcmp(token, "segstr"))
223 odp->u.func.arg_types[i] = 'T';
224 else if (!strcmp(token, "double"))
226 odp->u.func.arg_types[i++] = 'l';
227 if (i < sizeof(odp->u.func.arg_types)) odp->u.func.arg_types[i] = 'l';
229 else fatal_error( "Unknown variable type '%s'\n", token );
231 if (SpecType == SPEC_WIN32)
233 if (strcmp(token, "long") &&
234 strcmp(token, "ptr") &&
235 strcmp(token, "str") &&
236 strcmp(token, "wstr") &&
237 strcmp(token, "double"))
239 fatal_error( "Type '%s' not supported for Win32\n", token );
243 if ((*token != ')') || (i >= sizeof(odp->u.func.arg_types)))
244 fatal_error( "Too many arguments\n" );
246 odp->u.func.arg_types[i] = '\0';
247 if (odp->type == TYPE_VARARGS)
248 odp->flags |= FLAG_NORELAY; /* no relay debug possible for varags entry point */
249 odp->link_name = xstrdup( GetToken(0) );
250 if (strchr( odp->link_name, '.' ))
252 if (SpecType == SPEC_WIN16) fatal_error( "Forwarded functions not supported for Win16\n" );
253 odp->flags |= FLAG_FORWARD;
258 /*******************************************************************
261 * Parse an 'equate' definition.
263 static void ParseEquate( ORDDEF *odp )
267 const char *token = GetToken(0);
268 int value = strtol(token, &endptr, 0);
269 if (endptr == NULL || *endptr != '\0')
270 fatal_error( "Expected number value, got '%s'\n", token );
271 if (SpecType == SPEC_WIN32)
272 fatal_error( "'equate' not supported for Win32\n" );
273 odp->u.abs.value = value;
277 /*******************************************************************
280 * Parse a 'stub' definition.
282 static void ParseStub( ORDDEF *odp )
284 odp->u.func.arg_types[0] = '\0';
285 odp->link_name = xstrdup("");
289 /*******************************************************************
292 * Parse an 'extern' definition.
294 static void ParseExtern( ORDDEF *odp )
296 if (SpecType == SPEC_WIN16)
297 fatal_error( "'extern' not supported for Win16, use 'variable' instead\n" );
298 odp->link_name = xstrdup( GetToken(0) );
299 if (strchr( odp->link_name, '.' )) odp->flags |= FLAG_FORWARD;
303 /*******************************************************************
306 * Parse the optional flags for an entry point
308 static const char *ParseFlags( ORDDEF *odp )
316 for (i = 0; FlagNames[i]; i++)
317 if (!strcmp( FlagNames[i], token )) break;
318 if (!FlagNames[i]) fatal_error( "Unknown flag '%s'\n", token );
319 odp->flags |= 1 << i;
321 } while (*token == '-');
326 /*******************************************************************
329 * Fix an exported function name by removing a possible @xx suffix
331 static void fix_export_name( char *name )
333 char *p, *end = strrchr( name, '@' );
334 if (!end || !end[1] || end == name) return;
335 /* make sure all the rest is digits */
336 for (p = end + 1; *p; p++) if (!isdigit(*p)) return;
340 /*******************************************************************
343 * Parse an ordinal definition.
345 static void ParseOrdinal(int ordinal)
349 ORDDEF *odp = xmalloc( sizeof(*odp) );
350 memset( odp, 0, sizeof(*odp) );
351 EntryPoints[nb_entry_points++] = odp;
355 for (odp->type = 0; odp->type < TYPE_NBTYPES; odp->type++)
356 if (TypeNames[odp->type] && !strcmp( token, TypeNames[odp->type] ))
359 if (odp->type >= TYPE_NBTYPES)
360 fatal_error( "Expected type after ordinal, found '%s' instead\n", token );
363 if (*token == '-') token = ParseFlags( odp );
365 odp->name = xstrdup( token );
366 fix_export_name( odp->name );
367 odp->lineno = current_line;
368 odp->ordinal = ordinal;
373 ParseVariable( odp );
380 ParseExportFunction( odp );
396 if (odp->flags & FLAG_I386)
398 /* ignore this entry point on non-Intel archs */
399 EntryPoints[--nb_entry_points] = NULL;
407 if (!ordinal) fatal_error( "Ordinal 0 is not valid\n" );
408 if (ordinal >= MAX_ORDINALS) fatal_error( "Ordinal number %d too large\n", ordinal );
409 if (ordinal > Limit) Limit = ordinal;
410 if (ordinal < Base) Base = ordinal;
411 odp->ordinal = ordinal;
412 Ordinals[ordinal] = odp;
415 if (!strcmp( odp->name, "@" ) || odp->flags & FLAG_NONAME)
418 fatal_error( "Nameless function needs an explicit ordinal number\n" );
419 if (SpecType != SPEC_WIN32)
420 fatal_error( "Nameless functions not supported for Win16\n" );
421 if (!strcmp( odp->name, "@" )) free( odp->name );
422 else odp->export_name = odp->name;
425 else Names[nb_names++] = odp;
429 static int name_compare( const void *name1, const void *name2 )
431 ORDDEF *odp1 = *(ORDDEF **)name1;
432 ORDDEF *odp2 = *(ORDDEF **)name2;
433 return strcmp( odp1->name, odp2->name );
436 /*******************************************************************
439 * Sort the name array and catch duplicates.
441 static void sort_names(void)
445 if (!nb_names) return;
447 /* sort the list of names */
448 qsort( Names, nb_names, sizeof(Names[0]), name_compare );
450 /* check for duplicate names */
451 for (i = 0; i < nb_names - 1; i++)
453 if (!strcmp( Names[i]->name, Names[i+1]->name ))
455 current_line = max( Names[i]->lineno, Names[i+1]->lineno );
456 fatal_error( "'%s' redefined\n%s:%d: First defined here\n",
457 Names[i]->name, input_file_name,
458 min( Names[i]->lineno, Names[i+1]->lineno ) );
464 /*******************************************************************
469 void ParseTopLevel( FILE *file )
476 while ((token = GetToken(1)) != NULL)
478 if (strcmp(token, "@") == 0)
480 if (SpecType != SPEC_WIN32)
481 fatal_error( "'@' ordinals not supported for Win16\n" );
484 else if (IsNumberString(token))
486 ParseOrdinal( atoi(token) );
489 fatal_error( "Expected ordinal declaration\n" );
492 current_line = 0; /* no longer parsing the input file */
497 /*******************************************************************
500 static void add_debug_channel( const char *name )
504 for (i = 0; i < nb_debug_channels; i++)
505 if (!strcmp( debug_channels[i], name )) return;
507 debug_channels = xrealloc( debug_channels, (nb_debug_channels + 1) * sizeof(*debug_channels));
508 debug_channels[nb_debug_channels++] = xstrdup(name);
512 /*******************************************************************
513 * parse_debug_channels
515 * Parse a source file and extract the debug channel definitions.
517 void parse_debug_channels( const char *srcdir, const char *filename )
522 file = open_input_file( srcdir, filename );
523 while (fgets( ParseBuffer, sizeof(ParseBuffer), file ))
525 char *channel, *end, *p = ParseBuffer;
527 p = ParseBuffer + strlen(ParseBuffer) - 1;
528 if (!eol_seen) /* continuation line */
530 eol_seen = (*p == '\n');
533 if ((eol_seen = (*p == '\n'))) *p = 0;
536 while (isspace(*p)) p++;
537 if (!memcmp( p, "WINE_DECLARE_DEBUG_CHANNEL", 26 ) ||
538 !memcmp( p, "WINE_DEFAULT_DEBUG_CHANNEL", 26 ))
541 while (isspace(*p)) p++;
543 fatal_error( "invalid debug channel specification '%s'\n", ParseBuffer );
545 while (isspace(*p)) p++;
547 fatal_error( "invalid debug channel specification '%s'\n", ParseBuffer );
549 while (isalnum(*p) || *p == '_') p++;
551 while (isspace(*p)) p++;
553 fatal_error( "invalid debug channel specification '%s'\n", ParseBuffer );
555 add_debug_channel( channel );
559 close_input_file( file );