The init function can be called main.
[wine/dcerpc.git] / tools / winebuild / parser.c
blob897c6e972111dbc6647c781ce9c1bef71aa619fe
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
9 */
11 #include <assert.h>
12 #include <ctype.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
18 #include "config.h"
19 #include "winbase.h"
20 #include "build.h"
22 int current_line = 0;
24 static SPEC_TYPE SpecType = SPEC_INVALID;
26 static char ParseBuffer[512];
27 static char *ParseNext = ParseBuffer;
28 static char ParseSaveChar;
29 static FILE *input_file;
31 static const char * const TypeNames[TYPE_NBTYPES] =
33 "variable", /* TYPE_VARIABLE */
34 "pascal16", /* TYPE_PASCAL_16 */
35 "pascal", /* TYPE_PASCAL */
36 "equate", /* TYPE_ABS */
37 "register", /* TYPE_REGISTER */
38 "interrupt", /* TYPE_INTERRUPT */
39 "stub", /* TYPE_STUB */
40 "stdcall", /* TYPE_STDCALL */
41 "cdecl", /* TYPE_CDECL */
42 "varargs", /* TYPE_VARARGS */
43 "extern", /* TYPE_EXTERN */
44 "forward" /* TYPE_FORWARD */
47 static const char * const FlagNames[] =
49 "noimport", /* FLAG_NOIMPORT */
50 "norelay", /* FLAG_NORELAY */
51 "ret64", /* FLAG_RET64 */
52 "i386", /* FLAG_I386 */
53 NULL
56 static int IsNumberString(char *s)
58 while (*s) if (!isdigit(*s++)) return 0;
59 return 1;
62 inline static int is_token_separator( char ch )
64 return (ch == '(' || ch == ')' || ch == '-');
67 static char * GetTokenInLine(void)
69 char *p;
70 char *token;
72 if (ParseNext != ParseBuffer)
74 if (ParseSaveChar == '\0')
75 return NULL;
76 *ParseNext = ParseSaveChar;
80 * Remove initial white space.
82 for (p = ParseNext; isspace(*p); p++)
85 if ((*p == '\0') || (*p == '#'))
86 return NULL;
89 * Find end of token.
91 token = p++;
92 if (!is_token_separator(*token))
93 while (*p != '\0' && !is_token_separator(*p) && !isspace(*p))
94 p++;
96 ParseSaveChar = *p;
97 ParseNext = p;
98 *p = '\0';
100 return token;
103 static char * GetToken( int allow_eof )
105 char *token;
107 while ((token = GetTokenInLine()) == NULL)
109 ParseNext = ParseBuffer;
110 while (1)
112 current_line++;
113 if (fgets(ParseBuffer, sizeof(ParseBuffer), input_file) == NULL)
115 if (!allow_eof) fatal_error( "Unexpected end of file\n" );
116 return NULL;
118 if (ParseBuffer[0] != '#')
119 break;
122 return token;
126 /*******************************************************************
127 * ParseDebug
129 * Parse a debug channel definition.
131 static void ParseDebug(void)
133 char *token = GetToken(0);
134 if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token );
135 for (;;)
137 token = GetToken(0);
138 if (*token == ')') break;
139 debug_channels = xrealloc( debug_channels,
140 (nb_debug_channels + 1) * sizeof(*debug_channels));
141 debug_channels[nb_debug_channels++] = xstrdup(token);
146 /*******************************************************************
147 * ParseVariable
149 * Parse a variable definition.
151 static void ParseVariable( ORDDEF *odp )
153 char *endptr;
154 int *value_array;
155 int n_values;
156 int value_array_size;
158 char *token = GetToken(0);
159 if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token );
161 n_values = 0;
162 value_array_size = 25;
163 value_array = xmalloc(sizeof(*value_array) * value_array_size);
165 for (;;)
167 token = GetToken(0);
168 if (*token == ')')
169 break;
171 value_array[n_values++] = strtol(token, &endptr, 0);
172 if (n_values == value_array_size)
174 value_array_size += 25;
175 value_array = xrealloc(value_array,
176 sizeof(*value_array) * value_array_size);
179 if (endptr == NULL || *endptr != '\0')
180 fatal_error( "Expected number value, got '%s'\n", token );
183 odp->u.var.n_values = n_values;
184 odp->u.var.values = xrealloc(value_array, sizeof(*value_array) * n_values);
188 /*******************************************************************
189 * ParseExportFunction
191 * Parse a function definition.
193 static void ParseExportFunction( ORDDEF *odp )
195 char *token;
196 unsigned int i;
198 switch(SpecType)
200 case SPEC_WIN16:
201 if (odp->type == TYPE_STDCALL)
202 fatal_error( "'stdcall' not supported for Win16\n" );
203 if (odp->type == TYPE_VARARGS)
204 fatal_error( "'varargs' not supported for Win16\n" );
205 break;
206 case SPEC_WIN32:
207 if ((odp->type == TYPE_PASCAL) || (odp->type == TYPE_PASCAL_16))
208 fatal_error( "'pascal' not supported for Win32\n" );
209 break;
210 default:
211 break;
214 token = GetToken(0);
215 if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token );
217 for (i = 0; i < sizeof(odp->u.func.arg_types); i++)
219 token = GetToken(0);
220 if (*token == ')')
221 break;
223 if (!strcmp(token, "word"))
224 odp->u.func.arg_types[i] = 'w';
225 else if (!strcmp(token, "s_word"))
226 odp->u.func.arg_types[i] = 's';
227 else if (!strcmp(token, "long") || !strcmp(token, "segptr"))
228 odp->u.func.arg_types[i] = 'l';
229 else if (!strcmp(token, "ptr"))
230 odp->u.func.arg_types[i] = 'p';
231 else if (!strcmp(token, "str"))
232 odp->u.func.arg_types[i] = 't';
233 else if (!strcmp(token, "wstr"))
234 odp->u.func.arg_types[i] = 'W';
235 else if (!strcmp(token, "segstr"))
236 odp->u.func.arg_types[i] = 'T';
237 else if (!strcmp(token, "double"))
239 odp->u.func.arg_types[i++] = 'l';
240 if (i < sizeof(odp->u.func.arg_types)) odp->u.func.arg_types[i] = 'l';
242 else fatal_error( "Unknown variable type '%s'\n", token );
244 if (SpecType == SPEC_WIN32)
246 if (strcmp(token, "long") &&
247 strcmp(token, "ptr") &&
248 strcmp(token, "str") &&
249 strcmp(token, "wstr") &&
250 strcmp(token, "double"))
252 fatal_error( "Type '%s' not supported for Win32\n", token );
256 if ((*token != ')') || (i >= sizeof(odp->u.func.arg_types)))
257 fatal_error( "Too many arguments\n" );
259 odp->u.func.arg_types[i] = '\0';
260 if ((odp->type == TYPE_STDCALL) && !i)
261 odp->type = TYPE_CDECL; /* stdcall is the same as cdecl for 0 args */
262 if (odp->type == TYPE_VARARGS)
263 odp->flags |= FLAG_NORELAY; /* no relay debug possible for varags entry point */
264 strcpy(odp->u.func.link_name, GetToken(0));
268 /*******************************************************************
269 * ParseEquate
271 * Parse an 'equate' definition.
273 static void ParseEquate( ORDDEF *odp )
275 char *endptr;
277 char *token = GetToken(0);
278 int value = strtol(token, &endptr, 0);
279 if (endptr == NULL || *endptr != '\0')
280 fatal_error( "Expected number value, got '%s'\n", token );
281 if (SpecType == SPEC_WIN32)
282 fatal_error( "'equate' not supported for Win32\n" );
283 odp->u.abs.value = value;
287 /*******************************************************************
288 * ParseStub
290 * Parse a 'stub' definition.
292 static void ParseStub( ORDDEF *odp )
294 odp->u.func.arg_types[0] = '\0';
295 odp->u.func.link_name[0] = '\0';
299 /*******************************************************************
300 * ParseInterrupt
302 * Parse an 'interrupt' definition.
304 static void ParseInterrupt( ORDDEF *odp )
306 char *token;
308 if (SpecType == SPEC_WIN32)
309 fatal_error( "'interrupt' not supported for Win32\n" );
311 token = GetToken(0);
312 if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token );
314 token = GetToken(0);
315 if (*token != ')') fatal_error( "Expected ')' got '%s'\n", token );
317 odp->u.func.arg_types[0] = '\0';
318 strcpy( odp->u.func.link_name, GetToken(0) );
322 /*******************************************************************
323 * ParseExtern
325 * Parse an 'extern' definition.
327 static void ParseExtern( ORDDEF *odp )
329 if (SpecType == SPEC_WIN16) fatal_error( "'extern' not supported for Win16\n" );
330 strcpy( odp->u.ext.link_name, GetToken(0) );
331 /* 'extern' definitions are not available for implicit import */
332 odp->flags |= FLAG_NOIMPORT;
336 /*******************************************************************
337 * ParseForward
339 * Parse a 'forward' definition.
341 static void ParseForward( ORDDEF *odp )
343 if (SpecType == SPEC_WIN16) fatal_error( "'forward' not supported for Win16\n" );
344 strcpy( odp->u.fwd.link_name, GetToken(0) );
348 /*******************************************************************
349 * ParseFlags
351 * Parse the optional flags for an entry point
353 static char *ParseFlags( ORDDEF *odp )
355 unsigned int i;
356 char *token;
360 token = GetToken(0);
361 for (i = 0; FlagNames[i]; i++)
362 if (!strcmp( FlagNames[i], token )) break;
363 if (!FlagNames[i]) fatal_error( "Unknown flag '%s'\n", token );
364 odp->flags |= 1 << i;
365 token = GetToken(0);
366 } while (*token == '-');
368 return token;
371 /*******************************************************************
372 * fix_export_name
374 * Fix an exported function name by removing a possible @xx suffix
376 static void fix_export_name( char *name )
378 char *p, *end = strrchr( name, '@' );
379 if (!end || !end[1] || end == name) return;
380 /* make sure all the rest is digits */
381 for (p = end + 1; *p; p++) if (!isdigit(*p)) return;
382 *end = 0;
385 /*******************************************************************
386 * ParseOrdinal
388 * Parse an ordinal definition.
390 static void ParseOrdinal(int ordinal)
392 char *token;
394 ORDDEF *odp = &EntryPoints[nb_entry_points++];
396 token = GetToken(0);
398 for (odp->type = 0; odp->type < TYPE_NBTYPES; odp->type++)
399 if (TypeNames[odp->type] && !strcmp( token, TypeNames[odp->type] ))
400 break;
402 if (odp->type >= TYPE_NBTYPES)
403 fatal_error( "Expected type after ordinal, found '%s' instead\n", token );
405 token = GetToken(0);
406 if (*token == '-') token = ParseFlags( odp );
408 strcpy( odp->name, token );
409 fix_export_name( odp->name );
410 odp->lineno = current_line;
411 odp->ordinal = ordinal;
413 switch(odp->type)
415 case TYPE_VARIABLE:
416 ParseVariable( odp );
417 break;
418 case TYPE_REGISTER:
419 case TYPE_PASCAL_16:
420 case TYPE_PASCAL:
421 case TYPE_STDCALL:
422 case TYPE_VARARGS:
423 case TYPE_CDECL:
424 ParseExportFunction( odp );
425 break;
426 case TYPE_INTERRUPT:
427 ParseInterrupt( odp );
428 break;
429 case TYPE_ABS:
430 ParseEquate( odp );
431 break;
432 case TYPE_STUB:
433 ParseStub( odp );
434 break;
435 case TYPE_EXTERN:
436 ParseExtern( odp );
437 break;
438 case TYPE_FORWARD:
439 ParseForward( odp );
440 break;
441 default:
442 assert( 0 );
445 #ifndef __i386__
446 if (odp->flags & FLAG_I386)
448 /* ignore this entry point on non-Intel archs */
449 nb_entry_points--;
450 memset( odp, 0, sizeof(*odp) );
451 return;
453 #endif
455 if (ordinal != -1)
457 if (ordinal >= MAX_ORDINALS) fatal_error( "Ordinal number %d too large\n", ordinal );
458 if (ordinal > Limit) Limit = ordinal;
459 if (ordinal < Base) Base = ordinal;
460 odp->ordinal = ordinal;
461 Ordinals[ordinal] = odp;
464 if (!strcmp( odp->name, "@" ))
466 if (ordinal == -1)
467 fatal_error( "Nameless function needs an explicit ordinal number\n" );
468 if (SpecType != SPEC_WIN32)
469 fatal_error( "Nameless functions not supported for Win16\n" );
470 odp->name[0] = 0;
472 else Names[nb_names++] = odp;
476 static int name_compare( const void *name1, const void *name2 )
478 ORDDEF *odp1 = *(ORDDEF **)name1;
479 ORDDEF *odp2 = *(ORDDEF **)name2;
480 return strcmp( odp1->name, odp2->name );
483 /*******************************************************************
484 * sort_names
486 * Sort the name array and catch duplicates.
488 static void sort_names(void)
490 int i;
492 if (!nb_names) return;
494 /* sort the list of names */
495 qsort( Names, nb_names, sizeof(Names[0]), name_compare );
497 /* check for duplicate names */
498 for (i = 0; i < nb_names - 1; i++)
500 if (!strcmp( Names[i]->name, Names[i+1]->name ))
502 current_line = max( Names[i]->lineno, Names[i+1]->lineno );
503 fatal_error( "'%s' redefined (previous definition at line %d)\n",
504 Names[i]->name, min( Names[i]->lineno, Names[i+1]->lineno ) );
510 /*******************************************************************
511 * ParseTopLevel
513 * Parse a spec file.
515 SPEC_TYPE ParseTopLevel( FILE *file )
517 char *token;
519 input_file = file;
520 current_line = 1;
521 while ((token = GetToken(1)) != NULL)
523 if (strcmp(token, "name") == 0)
525 strcpy(DLLName, GetToken(0));
527 else if (strcmp(token, "file") == 0)
529 strcpy(DLLFileName, GetToken(0));
530 strupper(DLLFileName);
532 else if (strcmp(token, "type") == 0)
534 token = GetToken(0);
535 if (!strcmp(token, "win16" )) SpecType = SPEC_WIN16;
536 else if (!strcmp(token, "win32" )) SpecType = SPEC_WIN32;
537 else fatal_error( "Type must be 'win16' or 'win32'\n" );
539 else if (strcmp(token, "mode") == 0)
541 token = GetToken(0);
542 if (!strcmp(token, "dll" )) SpecMode = SPEC_MODE_DLL;
543 else if (!strcmp(token, "guiexe" )) SpecMode = SPEC_MODE_GUIEXE;
544 else if (!strcmp(token, "cuiexe" )) SpecMode = SPEC_MODE_CUIEXE;
545 else if (!strcmp(token, "guiexe_no_main" )) SpecMode = SPEC_MODE_GUIEXE_NO_MAIN;
546 else if (!strcmp(token, "cuiexe_no_main" )) SpecMode = SPEC_MODE_CUIEXE_NO_MAIN;
547 else fatal_error( "Mode must be 'dll', 'guiexe', 'cuiexe', 'guiexe_no_main' or 'cuiexe_no_main'\n" );
549 else if (strcmp(token, "heap") == 0)
551 token = GetToken(0);
552 if (!IsNumberString(token)) fatal_error( "Expected number after heap\n" );
553 DLLHeapSize = atoi(token);
555 else if (strcmp(token, "init") == 0)
557 strcpy(DLLInitFunc, GetToken(0));
558 if (SpecType == SPEC_WIN16)
559 fatal_error( "init cannot be used for Win16 spec files\n" );
560 if (!DLLInitFunc[0])
561 fatal_error( "Expected function name after init\n" );
563 else if (strcmp(token, "import") == 0)
565 if (SpecType != SPEC_WIN32)
566 fatal_error( "Imports not supported for Win16\n" );
567 add_import_dll( GetToken(0) );
569 else if (strcmp(token, "rsrc") == 0)
571 if (SpecType != SPEC_WIN16) load_res32_file( GetToken(0) );
572 else load_res16_file( GetToken(0) );
574 else if (strcmp(token, "owner") == 0)
576 if (SpecType != SPEC_WIN16)
577 fatal_error( "Owner only supported for Win16 spec files\n" );
578 strcpy( owner_name, GetToken(0) );
580 else if (strcmp(token, "debug_channels") == 0)
582 if (SpecType != SPEC_WIN32)
583 fatal_error( "debug channels only supported for Win32 spec files\n" );
584 ParseDebug();
586 else if (strcmp(token, "@") == 0)
588 if (SpecType != SPEC_WIN32)
589 fatal_error( "'@' ordinals not supported for Win16\n" );
590 ParseOrdinal( -1 );
592 else if (IsNumberString(token))
594 ParseOrdinal( atoi(token) );
596 else
597 fatal_error( "Expected name, id, length or ordinal\n" );
600 if (!DLLFileName[0])
602 if (SpecMode == SPEC_MODE_DLL)
603 sprintf( DLLFileName, "%s.dll", DLLName );
604 else
605 sprintf( DLLFileName, "%s.exe", DLLName );
608 if (SpecType == SPEC_INVALID) fatal_error( "Missing 'type' declaration\n" );
609 if (SpecType == SPEC_WIN16 && !owner_name[0])
610 fatal_error( "'owner' not specified for Win16 dll\n" );
612 current_line = 0; /* no longer parsing the input file */
613 sort_names();
614 return SpecType;