Added support for defining forward functions as stdcall so that we can
[wine/wine-kai.git] / tools / winebuild / parser.c
blob4ba650673dc2f54abf3b328fd3521827ed3b910e
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 "norelay", /* FLAG_NORELAY */
61 "noname", /* FLAG_NONAME */
62 "ret64", /* FLAG_RET64 */
63 "i386", /* FLAG_I386 */
64 "register", /* FLAG_REGISTER */
65 "interrupt", /* FLAG_INTERRUPT */
66 NULL
69 static int IsNumberString(const char *s)
71 while (*s) if (!isdigit(*s++)) return 0;
72 return 1;
75 inline static int is_token_separator( char ch )
77 return (ch == '(' || ch == ')' || ch == '-');
80 static const char * GetTokenInLine(void)
82 char *p = ParseNext;
83 char *token = TokenBuffer;
86 * Remove initial white space.
88 while (isspace(*p)) p++;
90 if ((*p == '\0') || (*p == '#')) return NULL;
93 * Find end of token.
95 if (is_token_separator(*p))
97 /* a separator is always a complete token */
98 *token++ = *p++;
100 else while (*p != '\0' && !is_token_separator(*p) && !isspace(*p))
102 if (*p == '\\') p++;
103 if (*p) *token++ = *p++;
105 *token = '\0';
106 ParseNext = p;
107 return TokenBuffer;
110 static const char * GetToken( int allow_eof )
112 const char *token;
114 while ((token = GetTokenInLine()) == NULL)
116 ParseNext = ParseBuffer;
117 current_line++;
118 if (fgets(ParseBuffer, sizeof(ParseBuffer), input_file) == NULL)
120 if (!allow_eof) fatal_error( "Unexpected end of file\n" );
121 return NULL;
124 return token;
128 /*******************************************************************
129 * ParseVariable
131 * Parse a variable definition.
133 static void ParseVariable( ORDDEF *odp )
135 char *endptr;
136 int *value_array;
137 int n_values;
138 int value_array_size;
140 const char *token = GetToken(0);
141 if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token );
143 n_values = 0;
144 value_array_size = 25;
145 value_array = xmalloc(sizeof(*value_array) * value_array_size);
147 for (;;)
149 token = GetToken(0);
150 if (*token == ')')
151 break;
153 value_array[n_values++] = strtol(token, &endptr, 0);
154 if (n_values == value_array_size)
156 value_array_size += 25;
157 value_array = xrealloc(value_array,
158 sizeof(*value_array) * value_array_size);
161 if (endptr == NULL || *endptr != '\0')
162 fatal_error( "Expected number value, got '%s'\n", token );
165 odp->u.var.n_values = n_values;
166 odp->u.var.values = xrealloc(value_array, sizeof(*value_array) * n_values);
170 /*******************************************************************
171 * ParseExportFunction
173 * Parse a function definition.
175 static void ParseExportFunction( ORDDEF *odp )
177 const char *token;
178 unsigned int i;
180 switch(SpecType)
182 case SPEC_WIN16:
183 if (odp->type == TYPE_STDCALL)
184 fatal_error( "'stdcall' not supported for Win16\n" );
185 if (odp->type == TYPE_VARARGS)
186 fatal_error( "'varargs' not supported for Win16\n" );
187 break;
188 case SPEC_WIN32:
189 if ((odp->type == TYPE_PASCAL) || (odp->type == TYPE_PASCAL_16))
190 fatal_error( "'pascal' not supported for Win32\n" );
191 if (odp->flags & FLAG_INTERRUPT)
192 fatal_error( "'interrupt' not supported for Win32\n" );
193 break;
194 default:
195 break;
198 token = GetToken(0);
199 if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token );
201 for (i = 0; i < sizeof(odp->u.func.arg_types); i++)
203 token = GetToken(0);
204 if (*token == ')')
205 break;
207 if (!strcmp(token, "word"))
208 odp->u.func.arg_types[i] = 'w';
209 else if (!strcmp(token, "s_word"))
210 odp->u.func.arg_types[i] = 's';
211 else if (!strcmp(token, "long") || !strcmp(token, "segptr"))
212 odp->u.func.arg_types[i] = 'l';
213 else if (!strcmp(token, "ptr"))
214 odp->u.func.arg_types[i] = 'p';
215 else if (!strcmp(token, "str"))
216 odp->u.func.arg_types[i] = 't';
217 else if (!strcmp(token, "wstr"))
218 odp->u.func.arg_types[i] = 'W';
219 else if (!strcmp(token, "segstr"))
220 odp->u.func.arg_types[i] = 'T';
221 else if (!strcmp(token, "double"))
223 odp->u.func.arg_types[i++] = 'l';
224 if (i < sizeof(odp->u.func.arg_types)) odp->u.func.arg_types[i] = 'l';
226 else fatal_error( "Unknown variable type '%s'\n", token );
228 if (SpecType == SPEC_WIN32)
230 if (strcmp(token, "long") &&
231 strcmp(token, "ptr") &&
232 strcmp(token, "str") &&
233 strcmp(token, "wstr") &&
234 strcmp(token, "double"))
236 fatal_error( "Type '%s' not supported for Win32\n", token );
240 if ((*token != ')') || (i >= sizeof(odp->u.func.arg_types)))
241 fatal_error( "Too many arguments\n" );
243 odp->u.func.arg_types[i] = '\0';
244 if (odp->type == TYPE_VARARGS)
245 odp->flags |= FLAG_NORELAY; /* no relay debug possible for varags entry point */
246 odp->link_name = xstrdup( GetToken(0) );
247 if (strchr( odp->link_name, '.' ))
249 if (SpecType == SPEC_WIN16) fatal_error( "Forwarded functions not supported for Win16\n" );
250 odp->flags |= FLAG_FORWARD;
255 /*******************************************************************
256 * ParseEquate
258 * Parse an 'equate' definition.
260 static void ParseEquate( ORDDEF *odp )
262 char *endptr;
264 const char *token = GetToken(0);
265 int value = strtol(token, &endptr, 0);
266 if (endptr == NULL || *endptr != '\0')
267 fatal_error( "Expected number value, got '%s'\n", token );
268 if (SpecType == SPEC_WIN32)
269 fatal_error( "'equate' not supported for Win32\n" );
270 odp->u.abs.value = value;
274 /*******************************************************************
275 * ParseStub
277 * Parse a 'stub' definition.
279 static void ParseStub( ORDDEF *odp )
281 odp->u.func.arg_types[0] = '\0';
282 odp->link_name = xstrdup("");
286 /*******************************************************************
287 * ParseExtern
289 * Parse an 'extern' definition.
291 static void ParseExtern( ORDDEF *odp )
293 if (SpecType == SPEC_WIN16) fatal_error( "'extern' not supported for Win16\n" );
294 odp->link_name = xstrdup( GetToken(0) );
298 /*******************************************************************
299 * ParseForward
301 * Parse a 'forward' definition.
303 static void ParseForward( ORDDEF *odp )
305 if (SpecType == SPEC_WIN16) fatal_error( "'forward' not supported for Win16\n" );
306 odp->link_name = xstrdup( GetToken(0) );
307 odp->flags |= FLAG_FORWARD;
311 /*******************************************************************
312 * ParseFlags
314 * Parse the optional flags for an entry point
316 static const char *ParseFlags( ORDDEF *odp )
318 unsigned int i;
319 const char *token;
323 token = GetToken(0);
324 for (i = 0; FlagNames[i]; i++)
325 if (!strcmp( FlagNames[i], token )) break;
326 if (!FlagNames[i]) fatal_error( "Unknown flag '%s'\n", token );
327 odp->flags |= 1 << i;
328 token = GetToken(0);
329 } while (*token == '-');
331 return token;
334 /*******************************************************************
335 * fix_export_name
337 * Fix an exported function name by removing a possible @xx suffix
339 static void fix_export_name( char *name )
341 char *p, *end = strrchr( name, '@' );
342 if (!end || !end[1] || end == name) return;
343 /* make sure all the rest is digits */
344 for (p = end + 1; *p; p++) if (!isdigit(*p)) return;
345 *end = 0;
348 /*******************************************************************
349 * ParseOrdinal
351 * Parse an ordinal definition.
353 static void ParseOrdinal(int ordinal)
355 const char *token;
357 ORDDEF *odp = xmalloc( sizeof(*odp) );
358 memset( odp, 0, sizeof(*odp) );
359 EntryPoints[nb_entry_points++] = odp;
361 token = GetToken(0);
363 for (odp->type = 0; odp->type < TYPE_NBTYPES; odp->type++)
364 if (TypeNames[odp->type] && !strcmp( token, TypeNames[odp->type] ))
365 break;
367 if (odp->type >= TYPE_NBTYPES)
368 fatal_error( "Expected type after ordinal, found '%s' instead\n", token );
370 token = GetToken(0);
371 if (*token == '-') token = ParseFlags( odp );
373 odp->name = xstrdup( token );
374 fix_export_name( odp->name );
375 odp->lineno = current_line;
376 odp->ordinal = ordinal;
378 switch(odp->type)
380 case TYPE_VARIABLE:
381 ParseVariable( odp );
382 break;
383 case TYPE_PASCAL_16:
384 case TYPE_PASCAL:
385 case TYPE_STDCALL:
386 case TYPE_VARARGS:
387 case TYPE_CDECL:
388 ParseExportFunction( odp );
389 break;
390 case TYPE_ABS:
391 ParseEquate( odp );
392 break;
393 case TYPE_STUB:
394 ParseStub( odp );
395 break;
396 case TYPE_EXTERN:
397 ParseExtern( odp );
398 break;
399 case TYPE_FORWARD:
400 ParseForward( odp );
401 break;
402 default:
403 assert( 0 );
406 #ifndef __i386__
407 if (odp->flags & FLAG_I386)
409 /* ignore this entry point on non-Intel archs */
410 EntryPoints[--nb_entry_points] = NULL;
411 free( odp );
412 return;
414 #endif
416 if (ordinal != -1)
418 if (!ordinal) fatal_error( "Ordinal 0 is not valid\n" );
419 if (ordinal >= MAX_ORDINALS) fatal_error( "Ordinal number %d too large\n", ordinal );
420 if (ordinal > Limit) Limit = ordinal;
421 if (ordinal < Base) Base = ordinal;
422 odp->ordinal = ordinal;
423 Ordinals[ordinal] = odp;
426 if (!strcmp( odp->name, "@" ) || odp->flags & FLAG_NONAME)
428 if (ordinal == -1)
429 fatal_error( "Nameless function needs an explicit ordinal number\n" );
430 if (SpecType != SPEC_WIN32)
431 fatal_error( "Nameless functions not supported for Win16\n" );
432 if (!strcmp( odp->name, "@" )) free( odp->name );
433 else odp->export_name = odp->name;
434 odp->name = NULL;
436 else Names[nb_names++] = odp;
440 static int name_compare( const void *name1, const void *name2 )
442 ORDDEF *odp1 = *(ORDDEF **)name1;
443 ORDDEF *odp2 = *(ORDDEF **)name2;
444 return strcmp( odp1->name, odp2->name );
447 /*******************************************************************
448 * sort_names
450 * Sort the name array and catch duplicates.
452 static void sort_names(void)
454 int i;
456 if (!nb_names) return;
458 /* sort the list of names */
459 qsort( Names, nb_names, sizeof(Names[0]), name_compare );
461 /* check for duplicate names */
462 for (i = 0; i < nb_names - 1; i++)
464 if (!strcmp( Names[i]->name, Names[i+1]->name ))
466 current_line = max( Names[i]->lineno, Names[i+1]->lineno );
467 fatal_error( "'%s' redefined\n%s:%d: First defined here\n",
468 Names[i]->name, input_file_name,
469 min( Names[i]->lineno, Names[i+1]->lineno ) );
475 /*******************************************************************
476 * ParseTopLevel
478 * Parse a spec file.
480 void ParseTopLevel( FILE *file )
482 const char *token;
484 input_file = file;
485 current_line = 0;
487 while ((token = GetToken(1)) != NULL)
489 if (strcmp(token, "@") == 0)
491 if (SpecType != SPEC_WIN32)
492 fatal_error( "'@' ordinals not supported for Win16\n" );
493 ParseOrdinal( -1 );
495 else if (IsNumberString(token))
497 ParseOrdinal( atoi(token) );
499 else
500 fatal_error( "Expected ordinal declaration\n" );
503 current_line = 0; /* no longer parsing the input file */
504 sort_names();
508 /*******************************************************************
509 * add_debug_channel
511 static void add_debug_channel( const char *name )
513 int i;
515 for (i = 0; i < nb_debug_channels; i++)
516 if (!strcmp( debug_channels[i], name )) return;
518 debug_channels = xrealloc( debug_channels, (nb_debug_channels + 1) * sizeof(*debug_channels));
519 debug_channels[nb_debug_channels++] = xstrdup(name);
523 /*******************************************************************
524 * parse_debug_channels
526 * Parse a source file and extract the debug channel definitions.
528 void parse_debug_channels( const char *srcdir, const char *filename )
530 FILE *file;
531 int eol_seen = 1;
533 file = open_input_file( srcdir, filename );
534 while (fgets( ParseBuffer, sizeof(ParseBuffer), file ))
536 char *channel, *end, *p = ParseBuffer;
538 p = ParseBuffer + strlen(ParseBuffer) - 1;
539 if (!eol_seen) /* continuation line */
541 eol_seen = (*p == '\n');
542 continue;
544 if ((eol_seen = (*p == '\n'))) *p = 0;
546 p = ParseBuffer;
547 while (isspace(*p)) p++;
548 if (!memcmp( p, "WINE_DECLARE_DEBUG_CHANNEL", 26 ) ||
549 !memcmp( p, "WINE_DEFAULT_DEBUG_CHANNEL", 26 ))
551 p += 26;
552 while (isspace(*p)) p++;
553 if (*p != '(')
554 fatal_error( "invalid debug channel specification '%s'\n", ParseBuffer );
555 p++;
556 while (isspace(*p)) p++;
557 if (!isalpha(*p))
558 fatal_error( "invalid debug channel specification '%s'\n", ParseBuffer );
559 channel = p;
560 while (isalnum(*p) || *p == '_') p++;
561 end = p;
562 while (isspace(*p)) p++;
563 if (*p != ')')
564 fatal_error( "invalid debug channel specification '%s'\n", ParseBuffer );
565 *end = 0;
566 add_debug_channel( channel );
568 current_line++;
570 close_input_file( file );