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
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 "stdcall64", /* TYPE_STDCALL64 */
42 "cdecl", /* TYPE_CDECL */
43 "varargs", /* TYPE_VARARGS */
44 "extern", /* TYPE_EXTERN */
45 "forward" /* TYPE_FORWARD */
48 /* callback function used for stub functions */
49 #define STUB_CALLBACK \
50 ((SpecType == SPEC_WIN16) ? "RELAY_Unimplemented16": "RELAY_Unimplemented32")
52 static int IsNumberString(char *s)
54 while (*s) if (!isdigit(*s++)) return 0;
58 static char * GetTokenInLine(void)
63 if (ParseNext != ParseBuffer)
65 if (ParseSaveChar == '\0')
67 *ParseNext = ParseSaveChar;
71 * Remove initial white space.
73 for (p = ParseNext; isspace(*p); p++)
76 if ((*p == '\0') || (*p == '#'))
83 if (*token != '(' && *token != ')')
84 while (*p != '\0' && *p != '(' && *p != ')' && !isspace(*p))
94 static char * GetToken(void)
98 while ((token = GetTokenInLine()) == NULL)
100 ParseNext = ParseBuffer;
104 if (fgets(ParseBuffer, sizeof(ParseBuffer), input_file) == NULL)
106 if (ParseBuffer[0] != '#')
114 /*******************************************************************
117 * Parse a variable definition.
119 static void ParseVariable( ORDDEF *odp )
124 int value_array_size;
126 char *token = GetToken();
127 if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token );
130 value_array_size = 25;
131 value_array = xmalloc(sizeof(*value_array) * value_array_size);
133 while ((token = GetToken()) != NULL)
138 value_array[n_values++] = strtol(token, &endptr, 0);
139 if (n_values == value_array_size)
141 value_array_size += 25;
142 value_array = xrealloc(value_array,
143 sizeof(*value_array) * value_array_size);
146 if (endptr == NULL || *endptr != '\0')
147 fatal_error( "Expected number value, got '%s'\n", token );
151 fatal_error( "End of file in variable declaration\n" );
153 odp->u.var.n_values = n_values;
154 odp->u.var.values = xrealloc(value_array, sizeof(*value_array) * n_values);
158 /*******************************************************************
159 * ParseExportFunction
161 * Parse a function definition.
163 static void ParseExportFunction( ORDDEF *odp )
171 if (odp->type == TYPE_STDCALL || odp->type == TYPE_STDCALL64)
172 fatal_error( "'stdcall' not supported for Win16\n" );
173 if (odp->type == TYPE_VARARGS)
174 fatal_error( "'varargs' not supported for Win16\n" );
177 if ((odp->type == TYPE_PASCAL) || (odp->type == TYPE_PASCAL_16))
178 fatal_error( "'pascal' not supported for Win32\n" );
185 if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token );
187 for (i = 0; i < sizeof(odp->u.func.arg_types); i++)
193 if (!strcmp(token, "word"))
194 odp->u.func.arg_types[i] = 'w';
195 else if (!strcmp(token, "s_word"))
196 odp->u.func.arg_types[i] = 's';
197 else if (!strcmp(token, "long") || !strcmp(token, "segptr"))
198 odp->u.func.arg_types[i] = 'l';
199 else if (!strcmp(token, "ptr"))
200 odp->u.func.arg_types[i] = 'p';
201 else if (!strcmp(token, "str"))
202 odp->u.func.arg_types[i] = 't';
203 else if (!strcmp(token, "wstr"))
204 odp->u.func.arg_types[i] = 'W';
205 else if (!strcmp(token, "segstr"))
206 odp->u.func.arg_types[i] = 'T';
207 else if (!strcmp(token, "double"))
209 odp->u.func.arg_types[i++] = 'l';
210 if (i < sizeof(odp->u.func.arg_types)) odp->u.func.arg_types[i] = 'l';
212 else fatal_error( "Unknown variable type '%s'\n", token );
214 if (SpecType == SPEC_WIN32)
216 if (strcmp(token, "long") &&
217 strcmp(token, "ptr") &&
218 strcmp(token, "str") &&
219 strcmp(token, "wstr") &&
220 strcmp(token, "double"))
222 fatal_error( "Type '%s' not supported for Win32\n", token );
226 if ((*token != ')') || (i >= sizeof(odp->u.func.arg_types)))
227 fatal_error( "Too many arguments\n" );
229 odp->u.func.arg_types[i] = '\0';
230 if ((odp->type == TYPE_STDCALL) && !i)
231 odp->type = TYPE_CDECL; /* stdcall is the same as cdecl for 0 args */
232 strcpy(odp->u.func.link_name, GetToken());
236 /*******************************************************************
239 * Parse an 'equate' definition.
241 static void ParseEquate( ORDDEF *odp )
245 char *token = GetToken();
246 int value = strtol(token, &endptr, 0);
247 if (endptr == NULL || *endptr != '\0')
248 fatal_error( "Expected number value, got '%s'\n", token );
249 if (SpecType == SPEC_WIN32)
250 fatal_error( "'equate' not supported for Win32\n" );
251 odp->u.abs.value = value;
255 /*******************************************************************
258 * Parse a 'stub' definition.
260 static void ParseStub( ORDDEF *odp )
262 odp->u.func.arg_types[0] = '\0';
263 strcpy( odp->u.func.link_name, STUB_CALLBACK );
267 /*******************************************************************
270 * Parse an 'interrupt' definition.
272 static void ParseInterrupt( ORDDEF *odp )
276 if (SpecType == SPEC_WIN32)
277 fatal_error( "'interrupt' not supported for Win32\n" );
280 if (*token != '(') fatal_error( "Expected '(' got '%s'\n", token );
283 if (*token != ')') fatal_error( "Expected ')' got '%s'\n", token );
285 odp->u.func.arg_types[0] = '\0';
286 strcpy( odp->u.func.link_name, GetToken() );
290 /*******************************************************************
293 * Parse an 'extern' definition.
295 static void ParseExtern( ORDDEF *odp )
297 if (SpecType == SPEC_WIN16) fatal_error( "'extern' not supported for Win16\n" );
298 strcpy( odp->u.ext.link_name, GetToken() );
302 /*******************************************************************
305 * Parse a 'forward' definition.
307 static void ParseForward( ORDDEF *odp )
309 if (SpecType == SPEC_WIN16) fatal_error( "'forward' not supported for Win16\n" );
310 strcpy( odp->u.fwd.link_name, GetToken() );
314 /*******************************************************************
317 * Fix an exported function name by removing a possible @xx suffix
319 static void fix_export_name( char *name )
321 char *p, *end = strrchr( name, '@' );
322 if (!end || !end[1] || end == name) return;
323 /* make sure all the rest is digits */
324 for (p = end + 1; *p; p++) if (!isdigit(*p)) return;
328 /*******************************************************************
331 * Parse an ordinal definition.
333 static void ParseOrdinal(int ordinal)
337 ORDDEF *odp = &EntryPoints[nb_entry_points++];
339 if (!(token = GetToken())) fatal_error( "Expected type after ordinal\n" );
341 for (odp->type = 0; odp->type < TYPE_NBTYPES; odp->type++)
342 if (TypeNames[odp->type] && !strcmp( token, TypeNames[odp->type] ))
345 if (odp->type >= TYPE_NBTYPES)
346 fatal_error( "Expected type after ordinal, found '%s' instead\n", token );
348 if (!(token = GetToken())) fatal_error( "Expected name after type\n" );
350 strcpy( odp->name, token );
351 fix_export_name( odp->name );
352 odp->lineno = current_line;
353 odp->ordinal = ordinal;
360 ParseVariable( odp );
363 ParseExportFunction( odp );
365 /* ignore Win32 'register' routines on non-Intel archs */
366 if (SpecType == SPEC_WIN32)
379 ParseExportFunction( odp );
382 ParseInterrupt( odp );
402 if (ordinal >= MAX_ORDINALS) fatal_error( "Ordinal number %d too large\n", ordinal );
403 if (ordinal > Limit) Limit = ordinal;
404 if (ordinal < Base) Base = ordinal;
405 odp->ordinal = ordinal;
406 Ordinals[ordinal] = odp;
409 if (!strcmp( odp->name, "@" ))
412 fatal_error( "Nameless function needs an explicit ordinal number\n" );
413 if (SpecType != SPEC_WIN32)
414 fatal_error( "Nameless functions not supported for Win16\n" );
417 else Names[nb_names++] = odp;
421 /*******************************************************************
426 SPEC_TYPE ParseTopLevel( FILE *file )
432 while ((token = GetToken()) != NULL)
434 if (strcmp(token, "name") == 0)
436 strcpy(DLLName, GetToken());
438 else if (strcmp(token, "file") == 0)
440 strcpy(DLLFileName, GetToken());
441 strupper(DLLFileName);
443 else if (strcmp(token, "type") == 0)
446 if (!strcmp(token, "win16" )) SpecType = SPEC_WIN16;
447 else if (!strcmp(token, "win32" )) SpecType = SPEC_WIN32;
448 else fatal_error( "Type must be 'win16' or 'win32'\n" );
450 else if (strcmp(token, "mode") == 0)
453 if (!strcmp(token, "dll" )) SpecMode = SPEC_MODE_DLL;
454 else if (!strcmp(token, "guiexe" )) SpecMode = SPEC_MODE_GUIEXE;
455 else if (!strcmp(token, "cuiexe" )) SpecMode = SPEC_MODE_CUIEXE;
456 else if (!strcmp(token, "guiexe_no_main" )) SpecMode = SPEC_MODE_GUIEXE_NO_MAIN;
457 else if (!strcmp(token, "cuiexe_no_main" )) SpecMode = SPEC_MODE_CUIEXE_NO_MAIN;
458 else fatal_error( "Mode must be 'dll', 'guiexe', 'cuiexe', 'guiexe_no_main' or 'cuiexe_no_main'\n" );
460 else if (strcmp(token, "heap") == 0)
463 if (!IsNumberString(token)) fatal_error( "Expected number after heap\n" );
464 DLLHeapSize = atoi(token);
466 else if (strcmp(token, "init") == 0)
468 strcpy(DLLInitFunc, GetToken());
469 if (SpecType == SPEC_WIN16)
470 fatal_error( "init cannot be used for Win16 spec files\n" );
472 fatal_error( "Expected function name after init\n" );
473 if (!strcmp(DLLInitFunc, "main"))
474 fatal_error( "The init function cannot be named 'main'\n" );
476 else if (strcmp(token, "import") == 0)
478 if (SpecType != SPEC_WIN32)
479 fatal_error( "Imports not supported for Win16\n" );
480 add_import_dll( GetToken() );
482 else if (strcmp(token, "rsrc") == 0)
484 if (SpecType != SPEC_WIN16) load_res32_file( GetToken() );
485 else load_res16_file( GetToken() );
487 else if (strcmp(token, "owner") == 0)
489 if (SpecType != SPEC_WIN16)
490 fatal_error( "Owner only supported for Win16 spec files\n" );
491 strcpy( owner_name, GetToken() );
493 else if (strcmp(token, "@") == 0)
495 if (SpecType != SPEC_WIN32)
496 fatal_error( "'@' ordinals not supported for Win16\n" );
499 else if (IsNumberString(token))
501 ParseOrdinal( atoi(token) );
504 fatal_error( "Expected name, id, length or ordinal\n" );
509 if (SpecMode == SPEC_MODE_DLL)
510 sprintf( DLLFileName, "%s.dll", DLLName );
512 sprintf( DLLFileName, "%s.exe", DLLName );
515 if (SpecType == SPEC_INVALID) fatal_error( "Missing 'type' declaration\n" );
516 if (SpecType == SPEC_WIN16 && !owner_name[0])
517 fatal_error( "'owner' not specified for Win16 dll\n" );
519 current_line = 0; /* no longer parsing the input file */