Removed support for 'rsrc' spec file statement.
[wine/multimedia.git] / tools / winebuild / parser.c
blob44690dfcdd1a3aa46d3235ec43e1de65a46aa04c
1 /*
2 * Spec file parser
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
25 #include "config.h"
26 #include "wine/port.h"
28 #include <assert.h>
29 #include <ctype.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
34 #include "winbase.h"
35 #include "build.h"
37 int current_line = 0;
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 */
55 "forward" /* TYPE_FORWARD */
58 static const char * const FlagNames[] =
60 "noimport", /* FLAG_NOIMPORT */
61 "norelay", /* FLAG_NORELAY */
62 "noname", /* FLAG_NONAME */
63 "ret64", /* FLAG_RET64 */
64 "i386", /* FLAG_I386 */
65 "register", /* FLAG_REGISTER */
66 "interrupt", /* FLAG_INTERRUPT */
67 NULL
70 static int IsNumberString(const char *s)
72 while (*s) if (!isdigit(*s++)) return 0;
73 return 1;
76 inline static int is_token_separator( char ch )
78 return (ch == '(' || ch == ')' || ch == '-');
81 static const char * GetTokenInLine(void)
83 char *p = ParseNext;
84 char *token = TokenBuffer;
87 * Remove initial white space.
89 while (isspace(*p)) p++;
91 if ((*p == '\0') || (*p == '#')) return NULL;
94 * Find end of token.
96 if (is_token_separator(*p))
98 /* a separator is always a complete token */
99 *token++ = *p++;
101 else while (*p != '\0' && !is_token_separator(*p) && !isspace(*p))
103 if (*p == '\\') p++;
104 if (*p) *token++ = *p++;
106 *token = '\0';
107 ParseNext = p;
108 return TokenBuffer;
111 static const char * GetToken( int allow_eof )
113 const char *token;
115 while ((token = GetTokenInLine()) == NULL)
117 ParseNext = ParseBuffer;
118 current_line++;
119 if (fgets(ParseBuffer, sizeof(ParseBuffer), input_file) == NULL)
121 if (!allow_eof) fatal_error( "Unexpected end of file\n" );
122 return NULL;
125 return token;
129 /*******************************************************************
130 * ParseIgnore
132 * Parse an 'ignore' definition.
134 static void ParseIgnore(void)
136 const char *token = GetToken(0);
137 if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token );
138 for (;;)
140 token = GetToken(0);
141 if (*token == ')') break;
142 add_ignore_symbol( token );
147 /*******************************************************************
148 * ParseVariable
150 * Parse a variable definition.
152 static void ParseVariable( ORDDEF *odp )
154 char *endptr;
155 int *value_array;
156 int n_values;
157 int value_array_size;
159 const char *token = GetToken(0);
160 if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token );
162 n_values = 0;
163 value_array_size = 25;
164 value_array = xmalloc(sizeof(*value_array) * value_array_size);
166 for (;;)
168 token = GetToken(0);
169 if (*token == ')')
170 break;
172 value_array[n_values++] = strtol(token, &endptr, 0);
173 if (n_values == value_array_size)
175 value_array_size += 25;
176 value_array = xrealloc(value_array,
177 sizeof(*value_array) * value_array_size);
180 if (endptr == NULL || *endptr != '\0')
181 fatal_error( "Expected number value, got '%s'\n", token );
184 odp->u.var.n_values = n_values;
185 odp->u.var.values = xrealloc(value_array, sizeof(*value_array) * n_values);
189 /*******************************************************************
190 * ParseExportFunction
192 * Parse a function definition.
194 static void ParseExportFunction( ORDDEF *odp )
196 const char *token;
197 unsigned int i;
199 switch(SpecType)
201 case SPEC_WIN16:
202 if (odp->type == TYPE_STDCALL)
203 fatal_error( "'stdcall' not supported for Win16\n" );
204 if (odp->type == TYPE_VARARGS)
205 fatal_error( "'varargs' not supported for Win16\n" );
206 break;
207 case SPEC_WIN32:
208 if ((odp->type == TYPE_PASCAL) || (odp->type == TYPE_PASCAL_16))
209 fatal_error( "'pascal' not supported for Win32\n" );
210 if (odp->flags & FLAG_INTERRUPT)
211 fatal_error( "'interrupt' not supported for Win32\n" );
212 break;
213 default:
214 break;
217 token = GetToken(0);
218 if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token );
220 for (i = 0; i < sizeof(odp->u.func.arg_types); i++)
222 token = GetToken(0);
223 if (*token == ')')
224 break;
226 if (!strcmp(token, "word"))
227 odp->u.func.arg_types[i] = 'w';
228 else if (!strcmp(token, "s_word"))
229 odp->u.func.arg_types[i] = 's';
230 else if (!strcmp(token, "long") || !strcmp(token, "segptr"))
231 odp->u.func.arg_types[i] = 'l';
232 else if (!strcmp(token, "ptr"))
233 odp->u.func.arg_types[i] = 'p';
234 else if (!strcmp(token, "str"))
235 odp->u.func.arg_types[i] = 't';
236 else if (!strcmp(token, "wstr"))
237 odp->u.func.arg_types[i] = 'W';
238 else if (!strcmp(token, "segstr"))
239 odp->u.func.arg_types[i] = 'T';
240 else if (!strcmp(token, "double"))
242 odp->u.func.arg_types[i++] = 'l';
243 if (i < sizeof(odp->u.func.arg_types)) odp->u.func.arg_types[i] = 'l';
245 else fatal_error( "Unknown variable type '%s'\n", token );
247 if (SpecType == SPEC_WIN32)
249 if (strcmp(token, "long") &&
250 strcmp(token, "ptr") &&
251 strcmp(token, "str") &&
252 strcmp(token, "wstr") &&
253 strcmp(token, "double"))
255 fatal_error( "Type '%s' not supported for Win32\n", token );
259 if ((*token != ')') || (i >= sizeof(odp->u.func.arg_types)))
260 fatal_error( "Too many arguments\n" );
262 odp->u.func.arg_types[i] = '\0';
263 if (odp->type == TYPE_VARARGS)
264 odp->flags |= FLAG_NORELAY; /* no relay debug possible for varags entry point */
265 odp->link_name = xstrdup( GetToken(0) );
269 /*******************************************************************
270 * ParseEquate
272 * Parse an 'equate' definition.
274 static void ParseEquate( ORDDEF *odp )
276 char *endptr;
278 const char *token = GetToken(0);
279 int value = strtol(token, &endptr, 0);
280 if (endptr == NULL || *endptr != '\0')
281 fatal_error( "Expected number value, got '%s'\n", token );
282 if (SpecType == SPEC_WIN32)
283 fatal_error( "'equate' not supported for Win32\n" );
284 odp->u.abs.value = value;
288 /*******************************************************************
289 * ParseStub
291 * Parse a 'stub' definition.
293 static void ParseStub( ORDDEF *odp )
295 odp->u.func.arg_types[0] = '\0';
296 odp->link_name = xstrdup("");
300 /*******************************************************************
301 * ParseExtern
303 * Parse an 'extern' definition.
305 static void ParseExtern( ORDDEF *odp )
307 if (SpecType == SPEC_WIN16) fatal_error( "'extern' not supported for Win16\n" );
308 odp->link_name = xstrdup( GetToken(0) );
309 /* 'extern' definitions are not available for implicit import */
310 odp->flags |= FLAG_NOIMPORT;
314 /*******************************************************************
315 * ParseForward
317 * Parse a 'forward' definition.
319 static void ParseForward( ORDDEF *odp )
321 if (SpecType == SPEC_WIN16) fatal_error( "'forward' not supported for Win16\n" );
322 odp->link_name = xstrdup( GetToken(0) );
326 /*******************************************************************
327 * ParseFlags
329 * Parse the optional flags for an entry point
331 static const char *ParseFlags( ORDDEF *odp )
333 unsigned int i;
334 const char *token;
338 token = GetToken(0);
339 for (i = 0; FlagNames[i]; i++)
340 if (!strcmp( FlagNames[i], token )) break;
341 if (!FlagNames[i]) fatal_error( "Unknown flag '%s'\n", token );
342 odp->flags |= 1 << i;
343 token = GetToken(0);
344 } while (*token == '-');
346 return token;
349 /*******************************************************************
350 * fix_export_name
352 * Fix an exported function name by removing a possible @xx suffix
354 static void fix_export_name( char *name )
356 char *p, *end = strrchr( name, '@' );
357 if (!end || !end[1] || end == name) return;
358 /* make sure all the rest is digits */
359 for (p = end + 1; *p; p++) if (!isdigit(*p)) return;
360 *end = 0;
363 /*******************************************************************
364 * ParseOrdinal
366 * Parse an ordinal definition.
368 static void ParseOrdinal(int ordinal)
370 const char *token;
372 ORDDEF *odp = xmalloc( sizeof(*odp) );
373 memset( odp, 0, sizeof(*odp) );
374 EntryPoints[nb_entry_points++] = odp;
376 token = GetToken(0);
378 for (odp->type = 0; odp->type < TYPE_NBTYPES; odp->type++)
379 if (TypeNames[odp->type] && !strcmp( token, TypeNames[odp->type] ))
380 break;
382 if (odp->type >= TYPE_NBTYPES)
383 fatal_error( "Expected type after ordinal, found '%s' instead\n", token );
385 token = GetToken(0);
386 if (*token == '-') token = ParseFlags( odp );
388 odp->name = xstrdup( token );
389 fix_export_name( odp->name );
390 odp->lineno = current_line;
391 odp->ordinal = ordinal;
393 switch(odp->type)
395 case TYPE_VARIABLE:
396 ParseVariable( odp );
397 break;
398 case TYPE_PASCAL_16:
399 case TYPE_PASCAL:
400 case TYPE_STDCALL:
401 case TYPE_VARARGS:
402 case TYPE_CDECL:
403 ParseExportFunction( odp );
404 break;
405 case TYPE_ABS:
406 ParseEquate( odp );
407 break;
408 case TYPE_STUB:
409 ParseStub( odp );
410 break;
411 case TYPE_EXTERN:
412 ParseExtern( odp );
413 break;
414 case TYPE_FORWARD:
415 ParseForward( odp );
416 break;
417 default:
418 assert( 0 );
421 #ifndef __i386__
422 if (odp->flags & FLAG_I386)
424 /* ignore this entry point on non-Intel archs */
425 EntryPoints[--nb_entry_points] = NULL;
426 free( odp );
427 return;
429 #endif
431 if (ordinal != -1)
433 if (!ordinal) fatal_error( "Ordinal 0 is not valid\n" );
434 if (ordinal >= MAX_ORDINALS) fatal_error( "Ordinal number %d too large\n", ordinal );
435 if (ordinal > Limit) Limit = ordinal;
436 if (ordinal < Base) Base = ordinal;
437 odp->ordinal = ordinal;
438 Ordinals[ordinal] = odp;
441 if (!strcmp( odp->name, "@" ) || odp->flags & FLAG_NONAME)
443 if (ordinal == -1)
444 fatal_error( "Nameless function needs an explicit ordinal number\n" );
445 if (SpecType != SPEC_WIN32)
446 fatal_error( "Nameless functions not supported for Win16\n" );
447 if (!strcmp( odp->name, "@" )) free( odp->name );
448 else odp->export_name = odp->name;
449 odp->name = NULL;
451 else Names[nb_names++] = odp;
455 static int name_compare( const void *name1, const void *name2 )
457 ORDDEF *odp1 = *(ORDDEF **)name1;
458 ORDDEF *odp2 = *(ORDDEF **)name2;
459 return strcmp( odp1->name, odp2->name );
462 /*******************************************************************
463 * sort_names
465 * Sort the name array and catch duplicates.
467 static void sort_names(void)
469 int i;
471 if (!nb_names) return;
473 /* sort the list of names */
474 qsort( Names, nb_names, sizeof(Names[0]), name_compare );
476 /* check for duplicate names */
477 for (i = 0; i < nb_names - 1; i++)
479 if (!strcmp( Names[i]->name, Names[i+1]->name ))
481 current_line = max( Names[i]->lineno, Names[i+1]->lineno );
482 fatal_error( "'%s' redefined\n%s:%d: First defined here\n",
483 Names[i]->name, input_file_name,
484 min( Names[i]->lineno, Names[i+1]->lineno ) );
490 /*******************************************************************
491 * ParseTopLevel
493 * Parse a spec file.
495 void ParseTopLevel( FILE *file )
497 const char *token;
499 input_file = file;
500 current_line = 0;
502 while ((token = GetToken(1)) != NULL)
504 if (strcmp(token, "ignore") == 0)
506 if (SpecType != SPEC_WIN32)
507 fatal_error( "'ignore' only supported for Win32 spec files\n" );
508 ParseIgnore();
510 else if (strcmp(token, "@") == 0)
512 if (SpecType != SPEC_WIN32)
513 fatal_error( "'@' ordinals not supported for Win16\n" );
514 ParseOrdinal( -1 );
516 else if (IsNumberString(token))
518 ParseOrdinal( atoi(token) );
520 else
521 fatal_error( "Expected ordinal declaration\n" );
524 current_line = 0; /* no longer parsing the input file */
525 sort_names();
529 /*******************************************************************
530 * add_debug_channel
532 static void add_debug_channel( const char *name )
534 int i;
536 for (i = 0; i < nb_debug_channels; i++)
537 if (!strcmp( debug_channels[i], name )) return;
539 debug_channels = xrealloc( debug_channels, (nb_debug_channels + 1) * sizeof(*debug_channels));
540 debug_channels[nb_debug_channels++] = xstrdup(name);
544 /*******************************************************************
545 * parse_debug_channels
547 * Parse a source file and extract the debug channel definitions.
549 void parse_debug_channels( const char *srcdir, const char *filename )
551 FILE *file;
552 int eol_seen = 1;
554 file = open_input_file( srcdir, filename );
555 while (fgets( ParseBuffer, sizeof(ParseBuffer), file ))
557 char *channel, *end, *p = ParseBuffer;
559 p = ParseBuffer + strlen(ParseBuffer) - 1;
560 if (!eol_seen) /* continuation line */
562 eol_seen = (*p == '\n');
563 continue;
565 if ((eol_seen = (*p == '\n'))) *p = 0;
567 p = ParseBuffer;
568 while (isspace(*p)) p++;
569 if (!memcmp( p, "WINE_DECLARE_DEBUG_CHANNEL", 26 ) ||
570 !memcmp( p, "WINE_DEFAULT_DEBUG_CHANNEL", 26 ))
572 p += 26;
573 while (isspace(*p)) p++;
574 if (*p != '(')
575 fatal_error( "invalid debug channel specification '%s'\n", ParseBuffer );
576 p++;
577 while (isspace(*p)) p++;
578 if (!isalpha(*p))
579 fatal_error( "invalid debug channel specification '%s'\n", ParseBuffer );
580 channel = p;
581 while (isalnum(*p) || *p == '_') p++;
582 end = p;
583 while (isspace(*p)) p++;
584 if (*p != ')')
585 fatal_error( "invalid debug channel specification '%s'\n", ParseBuffer );
586 *end = 0;
587 add_debug_channel( channel );
589 current_line++;
591 close_input_file( file );