Started implementation of the functions GetDefaultCommConfigA/W.
[wine/multimedia.git] / tools / winebuild / parser.c
blob7d05f8cd5d28ea0a041b97fb7406e14cb86e3508
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 "build.h"
20 int current_line = 0;
22 static SPEC_TYPE SpecType = SPEC_INVALID;
24 static char ParseBuffer[512];
25 static char *ParseNext = ParseBuffer;
26 static char ParseSaveChar;
27 static FILE *input_file;
29 static const char * const TypeNames[TYPE_NBTYPES] =
31 "byte", /* TYPE_BYTE */
32 "word", /* TYPE_WORD */
33 "long", /* TYPE_LONG */
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 /* callback function used for stub functions */
48 #define STUB_CALLBACK \
49 ((SpecType == SPEC_WIN16) ? "RELAY_Unimplemented16": "RELAY_Unimplemented32")
51 static int IsNumberString(char *s)
53 while (*s) if (!isdigit(*s++)) return 0;
54 return 1;
57 static char * GetTokenInLine(void)
59 char *p;
60 char *token;
62 if (ParseNext != ParseBuffer)
64 if (ParseSaveChar == '\0')
65 return NULL;
66 *ParseNext = ParseSaveChar;
70 * Remove initial white space.
72 for (p = ParseNext; isspace(*p); p++)
75 if ((*p == '\0') || (*p == '#'))
76 return NULL;
79 * Find end of token.
81 token = p++;
82 if (*token != '(' && *token != ')')
83 while (*p != '\0' && *p != '(' && *p != ')' && !isspace(*p))
84 p++;
86 ParseSaveChar = *p;
87 ParseNext = p;
88 *p = '\0';
90 return token;
93 static char * GetToken(void)
95 char *token;
97 while ((token = GetTokenInLine()) == NULL)
99 ParseNext = ParseBuffer;
100 while (1)
102 current_line++;
103 if (fgets(ParseBuffer, sizeof(ParseBuffer), input_file) == NULL)
104 return NULL;
105 if (ParseBuffer[0] != '#')
106 break;
109 return token;
113 /*******************************************************************
114 * ParseVariable
116 * Parse a variable definition.
118 static void ParseVariable( ORDDEF *odp )
120 char *endptr;
121 int *value_array;
122 int n_values;
123 int value_array_size;
125 char *token = GetToken();
126 if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token );
128 n_values = 0;
129 value_array_size = 25;
130 value_array = xmalloc(sizeof(*value_array) * value_array_size);
132 while ((token = GetToken()) != NULL)
134 if (*token == ')')
135 break;
137 value_array[n_values++] = strtol(token, &endptr, 0);
138 if (n_values == value_array_size)
140 value_array_size += 25;
141 value_array = xrealloc(value_array,
142 sizeof(*value_array) * value_array_size);
145 if (endptr == NULL || *endptr != '\0')
146 fatal_error( "Expected number value, got '%s'\n", token );
149 if (token == NULL)
150 fatal_error( "End of file in variable declaration\n" );
152 odp->u.var.n_values = n_values;
153 odp->u.var.values = xrealloc(value_array, sizeof(*value_array) * n_values);
157 /*******************************************************************
158 * ParseExportFunction
160 * Parse a function definition.
162 static void ParseExportFunction( ORDDEF *odp )
164 char *token;
165 int i;
167 switch(SpecType)
169 case SPEC_WIN16:
170 if (odp->type == TYPE_STDCALL)
171 fatal_error( "'stdcall' not supported for Win16\n" );
172 if (odp->type == TYPE_VARARGS)
173 fatal_error( "'varargs' not supported for Win16\n" );
174 break;
175 case SPEC_WIN32:
176 if ((odp->type == TYPE_PASCAL) || (odp->type == TYPE_PASCAL_16))
177 fatal_error( "'pascal' not supported for Win32\n" );
178 break;
179 default:
180 break;
183 token = GetToken();
184 if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token );
186 for (i = 0; i < sizeof(odp->u.func.arg_types)-1; i++)
188 token = GetToken();
189 if (*token == ')')
190 break;
192 if (!strcmp(token, "word"))
193 odp->u.func.arg_types[i] = 'w';
194 else if (!strcmp(token, "s_word"))
195 odp->u.func.arg_types[i] = 's';
196 else if (!strcmp(token, "long") || !strcmp(token, "segptr"))
197 odp->u.func.arg_types[i] = 'l';
198 else if (!strcmp(token, "ptr"))
199 odp->u.func.arg_types[i] = 'p';
200 else if (!strcmp(token, "str"))
201 odp->u.func.arg_types[i] = 't';
202 else if (!strcmp(token, "wstr"))
203 odp->u.func.arg_types[i] = 'W';
204 else if (!strcmp(token, "segstr"))
205 odp->u.func.arg_types[i] = 'T';
206 else if (!strcmp(token, "double"))
208 odp->u.func.arg_types[i++] = 'l';
209 odp->u.func.arg_types[i] = 'l';
211 else fatal_error( "Unknown variable type '%s'\n", token );
213 if (SpecType == SPEC_WIN32)
215 if (strcmp(token, "long") &&
216 strcmp(token, "ptr") &&
217 strcmp(token, "str") &&
218 strcmp(token, "wstr") &&
219 strcmp(token, "double"))
221 fatal_error( "Type '%s' not supported for Win32\n", token );
225 if ((*token != ')') || (i >= sizeof(odp->u.func.arg_types)))
226 fatal_error( "Too many arguments\n" );
228 odp->u.func.arg_types[i] = '\0';
229 if ((odp->type == TYPE_STDCALL) && !i)
230 odp->type = TYPE_CDECL; /* stdcall is the same as cdecl for 0 args */
231 strcpy(odp->u.func.link_name, GetToken());
235 /*******************************************************************
236 * ParseEquate
238 * Parse an 'equate' definition.
240 static void ParseEquate( ORDDEF *odp )
242 char *endptr;
244 char *token = GetToken();
245 int value = strtol(token, &endptr, 0);
246 if (endptr == NULL || *endptr != '\0')
247 fatal_error( "Expected number value, got '%s'\n", token );
248 if (SpecType == SPEC_WIN32)
249 fatal_error( "'equate' not supported for Win32\n" );
250 odp->u.abs.value = value;
254 /*******************************************************************
255 * ParseStub
257 * Parse a 'stub' definition.
259 static void ParseStub( ORDDEF *odp )
261 odp->u.func.arg_types[0] = '\0';
262 strcpy( odp->u.func.link_name, STUB_CALLBACK );
266 /*******************************************************************
267 * ParseInterrupt
269 * Parse an 'interrupt' definition.
271 static void ParseInterrupt( ORDDEF *odp )
273 char *token;
275 if (SpecType == SPEC_WIN32)
276 fatal_error( "'interrupt' not supported for Win32\n" );
278 token = GetToken();
279 if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token );
281 token = GetToken();
282 if (*token != ')') fatal_error( "Expected ')' got '%s'\n", token );
284 odp->u.func.arg_types[0] = '\0';
285 strcpy( odp->u.func.link_name, GetToken() );
289 /*******************************************************************
290 * ParseExtern
292 * Parse an 'extern' definition.
294 static void ParseExtern( ORDDEF *odp )
296 if (SpecType == SPEC_WIN16) fatal_error( "'extern' not supported for Win16\n" );
297 strcpy( odp->u.ext.link_name, GetToken() );
301 /*******************************************************************
302 * ParseForward
304 * Parse a 'forward' definition.
306 static void ParseForward( ORDDEF *odp )
308 if (SpecType == SPEC_WIN16) fatal_error( "'forward' not supported for Win16\n" );
309 strcpy( odp->u.fwd.link_name, GetToken() );
313 /*******************************************************************
314 * ParseOrdinal
316 * Parse an ordinal definition.
318 static void ParseOrdinal(int ordinal)
320 char *token;
322 ORDDEF *odp = &EntryPoints[nb_entry_points++];
324 if (!(token = GetToken())) fatal_error( "Expected type after ordinal\n" );
326 for (odp->type = 0; odp->type < TYPE_NBTYPES; odp->type++)
327 if (TypeNames[odp->type] && !strcmp( token, TypeNames[odp->type] ))
328 break;
330 if (odp->type >= TYPE_NBTYPES)
331 fatal_error( "Expected type after ordinal, found '%s' instead\n", token );
333 if (!(token = GetToken())) fatal_error( "Expected name after type\n" );
335 strcpy( odp->name, token );
336 odp->lineno = current_line;
337 odp->ordinal = ordinal;
339 switch(odp->type)
341 case TYPE_BYTE:
342 case TYPE_WORD:
343 case TYPE_LONG:
344 ParseVariable( odp );
345 break;
346 case TYPE_REGISTER:
347 ParseExportFunction( odp );
348 #ifndef __i386__
349 /* ignore Win32 'register' routines on non-Intel archs */
350 if (SpecType == SPEC_WIN32)
352 nb_entry_points--;
353 return;
355 #endif
356 break;
357 case TYPE_PASCAL_16:
358 case TYPE_PASCAL:
359 case TYPE_STDCALL:
360 case TYPE_VARARGS:
361 case TYPE_CDECL:
362 ParseExportFunction( odp );
363 break;
364 case TYPE_INTERRUPT:
365 ParseInterrupt( odp );
366 break;
367 case TYPE_ABS:
368 ParseEquate( odp );
369 break;
370 case TYPE_STUB:
371 ParseStub( odp );
372 break;
373 case TYPE_EXTERN:
374 ParseExtern( odp );
375 break;
376 case TYPE_FORWARD:
377 ParseForward( odp );
378 break;
379 default:
380 assert( 0 );
383 if (ordinal != -1)
385 if (ordinal >= MAX_ORDINALS) fatal_error( "Ordinal number %d too large\n", ordinal );
386 if (ordinal > Limit) Limit = ordinal;
387 if (ordinal < Base) Base = ordinal;
388 odp->ordinal = ordinal;
389 Ordinals[ordinal] = odp;
392 if (!strcmp( odp->name, "@" ))
394 if (ordinal == -1)
395 fatal_error( "Nameless function needs an explicit ordinal number\n" );
396 if (SpecType != SPEC_WIN32)
397 fatal_error( "Nameless functions not supported for Win16\n" );
398 odp->name[0] = 0;
400 else Names[nb_names++] = odp;
404 /*******************************************************************
405 * ParseTopLevel
407 * Parse a spec file.
409 SPEC_TYPE ParseTopLevel( FILE *file )
411 char *token;
413 input_file = file;
414 current_line = 1;
415 while ((token = GetToken()) != NULL)
417 if (strcmp(token, "name") == 0)
419 strcpy(DLLName, GetToken());
421 else if (strcmp(token, "file") == 0)
423 strcpy(DLLFileName, GetToken());
424 strupper(DLLFileName);
426 else if (strcmp(token, "type") == 0)
428 token = GetToken();
429 if (!strcmp(token, "win16" )) SpecType = SPEC_WIN16;
430 else if (!strcmp(token, "win32" )) SpecType = SPEC_WIN32;
431 else fatal_error( "Type must be 'win16' or 'win32'\n" );
433 else if (strcmp(token, "mode") == 0)
435 token = GetToken();
436 if (!strcmp(token, "dll" )) SpecMode = SPEC_MODE_DLL;
437 else if (!strcmp(token, "guiexe" )) SpecMode = SPEC_MODE_GUIEXE;
438 else if (!strcmp(token, "cuiexe" )) SpecMode = SPEC_MODE_CUIEXE;
439 else fatal_error( "Mode must be 'dll', 'guiexe' or 'cuiexe'\n" );
441 else if (strcmp(token, "heap") == 0)
443 token = GetToken();
444 if (!IsNumberString(token)) fatal_error( "Expected number after heap\n" );
445 DLLHeapSize = atoi(token);
447 else if (strcmp(token, "init") == 0)
449 strcpy(DLLInitFunc, GetToken());
450 if (SpecType == SPEC_WIN16)
451 fatal_error( "init cannot be used for Win16 spec files\n" );
452 if (!DLLInitFunc[0])
453 fatal_error( "Expected function name after init\n" );
454 if (!strcmp(DLLInitFunc, "main"))
455 fatal_error( "The init function cannot be named 'main'\n" );
457 else if (strcmp(token, "import") == 0)
459 if (nb_imports >= MAX_IMPORTS)
460 fatal_error( "Too many imports (limit %d)\n", MAX_IMPORTS );
461 if (SpecType != SPEC_WIN32)
462 fatal_error( "Imports not supported for Win16\n" );
463 DLLImports[nb_imports++] = xstrdup(GetToken());
465 else if (strcmp(token, "rsrc") == 0)
467 strcpy( rsrc_name, GetToken() );
468 strcat( rsrc_name, "_ResourceDescriptor" );
470 else if (strcmp(token, "@") == 0)
472 if (SpecType != SPEC_WIN32)
473 fatal_error( "'@' ordinals not supported for Win16\n" );
474 ParseOrdinal( -1 );
476 else if (IsNumberString(token))
478 ParseOrdinal( atoi(token) );
480 else
481 fatal_error( "Expected name, id, length or ordinal\n" );
484 if (!DLLFileName[0])
486 if (SpecMode == SPEC_MODE_DLL)
487 sprintf( DLLFileName, "%s.dll", DLLName );
488 else
489 sprintf( DLLFileName, "%s.exe", DLLName );
492 if (SpecType == SPEC_INVALID) fatal_error( "Missing 'type' declaration\n" );
493 current_line = 0; /* no longer parsing the input file */
494 return SpecType;