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
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 */
56 static int IsNumberString(char *s
)
58 while (*s
) if (!isdigit(*s
++)) return 0;
62 inline static int is_token_separator( char ch
)
64 return (ch
== '(' || ch
== ')' || ch
== '-');
67 static char * GetTokenInLine(void)
72 if (ParseNext
!= ParseBuffer
)
74 if (ParseSaveChar
== '\0')
76 *ParseNext
= ParseSaveChar
;
80 * Remove initial white space.
82 for (p
= ParseNext
; isspace(*p
); p
++)
85 if ((*p
== '\0') || (*p
== '#'))
92 if (!is_token_separator(*token
))
93 while (*p
!= '\0' && !is_token_separator(*p
) && !isspace(*p
))
103 static char * GetToken( int allow_eof
)
107 while ((token
= GetTokenInLine()) == NULL
)
109 ParseNext
= ParseBuffer
;
113 if (fgets(ParseBuffer
, sizeof(ParseBuffer
), input_file
) == NULL
)
115 if (!allow_eof
) fatal_error( "Unexpected end of file\n" );
118 if (ParseBuffer
[0] != '#')
126 /*******************************************************************
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
);
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 /*******************************************************************
149 * Parse an 'ignore' definition.
151 static void ParseIgnore(void)
153 char *token
= GetToken(0);
154 if (*token
!= '(') fatal_error( "Expected '(' got '%s'\n", token
);
158 if (*token
== ')') break;
159 add_ignore_symbol( token
);
164 /*******************************************************************
167 * Parse a variable definition.
169 static void ParseVariable( ORDDEF
*odp
)
174 int value_array_size
;
176 char *token
= GetToken(0);
177 if (*token
!= '(') fatal_error( "Expected '(' got '%s'\n", token
);
180 value_array_size
= 25;
181 value_array
= xmalloc(sizeof(*value_array
) * value_array_size
);
189 value_array
[n_values
++] = strtol(token
, &endptr
, 0);
190 if (n_values
== value_array_size
)
192 value_array_size
+= 25;
193 value_array
= xrealloc(value_array
,
194 sizeof(*value_array
) * value_array_size
);
197 if (endptr
== NULL
|| *endptr
!= '\0')
198 fatal_error( "Expected number value, got '%s'\n", token
);
201 odp
->u
.var
.n_values
= n_values
;
202 odp
->u
.var
.values
= xrealloc(value_array
, sizeof(*value_array
) * n_values
);
206 /*******************************************************************
207 * ParseExportFunction
209 * Parse a function definition.
211 static void ParseExportFunction( ORDDEF
*odp
)
219 if (odp
->type
== TYPE_STDCALL
)
220 fatal_error( "'stdcall' not supported for Win16\n" );
221 if (odp
->type
== TYPE_VARARGS
)
222 fatal_error( "'varargs' not supported for Win16\n" );
225 if ((odp
->type
== TYPE_PASCAL
) || (odp
->type
== TYPE_PASCAL_16
))
226 fatal_error( "'pascal' not supported for Win32\n" );
233 if (*token
!= '(') fatal_error( "Expected '(' got '%s'\n", token
);
235 for (i
= 0; i
< sizeof(odp
->u
.func
.arg_types
); i
++)
241 if (!strcmp(token
, "word"))
242 odp
->u
.func
.arg_types
[i
] = 'w';
243 else if (!strcmp(token
, "s_word"))
244 odp
->u
.func
.arg_types
[i
] = 's';
245 else if (!strcmp(token
, "long") || !strcmp(token
, "segptr"))
246 odp
->u
.func
.arg_types
[i
] = 'l';
247 else if (!strcmp(token
, "ptr"))
248 odp
->u
.func
.arg_types
[i
] = 'p';
249 else if (!strcmp(token
, "str"))
250 odp
->u
.func
.arg_types
[i
] = 't';
251 else if (!strcmp(token
, "wstr"))
252 odp
->u
.func
.arg_types
[i
] = 'W';
253 else if (!strcmp(token
, "segstr"))
254 odp
->u
.func
.arg_types
[i
] = 'T';
255 else if (!strcmp(token
, "double"))
257 odp
->u
.func
.arg_types
[i
++] = 'l';
258 if (i
< sizeof(odp
->u
.func
.arg_types
)) odp
->u
.func
.arg_types
[i
] = 'l';
260 else fatal_error( "Unknown variable type '%s'\n", token
);
262 if (SpecType
== SPEC_WIN32
)
264 if (strcmp(token
, "long") &&
265 strcmp(token
, "ptr") &&
266 strcmp(token
, "str") &&
267 strcmp(token
, "wstr") &&
268 strcmp(token
, "double"))
270 fatal_error( "Type '%s' not supported for Win32\n", token
);
274 if ((*token
!= ')') || (i
>= sizeof(odp
->u
.func
.arg_types
)))
275 fatal_error( "Too many arguments\n" );
277 odp
->u
.func
.arg_types
[i
] = '\0';
278 if ((odp
->type
== TYPE_STDCALL
) && !i
)
279 odp
->type
= TYPE_CDECL
; /* stdcall is the same as cdecl for 0 args */
280 if (odp
->type
== TYPE_VARARGS
)
281 odp
->flags
|= FLAG_NORELAY
; /* no relay debug possible for varags entry point */
282 odp
->link_name
= xstrdup( GetToken(0) );
286 /*******************************************************************
289 * Parse an 'equate' definition.
291 static void ParseEquate( ORDDEF
*odp
)
295 char *token
= GetToken(0);
296 int value
= strtol(token
, &endptr
, 0);
297 if (endptr
== NULL
|| *endptr
!= '\0')
298 fatal_error( "Expected number value, got '%s'\n", token
);
299 if (SpecType
== SPEC_WIN32
)
300 fatal_error( "'equate' not supported for Win32\n" );
301 odp
->u
.abs
.value
= value
;
305 /*******************************************************************
308 * Parse a 'stub' definition.
310 static void ParseStub( ORDDEF
*odp
)
312 odp
->u
.func
.arg_types
[0] = '\0';
313 odp
->link_name
= xstrdup("");
317 /*******************************************************************
320 * Parse an 'interrupt' definition.
322 static void ParseInterrupt( ORDDEF
*odp
)
326 if (SpecType
== SPEC_WIN32
)
327 fatal_error( "'interrupt' not supported for Win32\n" );
330 if (*token
!= '(') fatal_error( "Expected '(' got '%s'\n", token
);
333 if (*token
!= ')') fatal_error( "Expected ')' got '%s'\n", token
);
335 odp
->u
.func
.arg_types
[0] = '\0';
336 odp
->link_name
= xstrdup( GetToken(0) );
340 /*******************************************************************
343 * Parse an 'extern' definition.
345 static void ParseExtern( ORDDEF
*odp
)
347 if (SpecType
== SPEC_WIN16
) fatal_error( "'extern' not supported for Win16\n" );
348 odp
->link_name
= xstrdup( GetToken(0) );
349 /* 'extern' definitions are not available for implicit import */
350 odp
->flags
|= FLAG_NOIMPORT
;
354 /*******************************************************************
357 * Parse a 'forward' definition.
359 static void ParseForward( ORDDEF
*odp
)
361 if (SpecType
== SPEC_WIN16
) fatal_error( "'forward' not supported for Win16\n" );
362 odp
->link_name
= xstrdup( GetToken(0) );
366 /*******************************************************************
369 * Parse the optional flags for an entry point
371 static char *ParseFlags( ORDDEF
*odp
)
379 for (i
= 0; FlagNames
[i
]; i
++)
380 if (!strcmp( FlagNames
[i
], token
)) break;
381 if (!FlagNames
[i
]) fatal_error( "Unknown flag '%s'\n", token
);
382 odp
->flags
|= 1 << i
;
384 } while (*token
== '-');
389 /*******************************************************************
392 * Fix an exported function name by removing a possible @xx suffix
394 static void fix_export_name( char *name
)
396 char *p
, *end
= strrchr( name
, '@' );
397 if (!end
|| !end
[1] || end
== name
) return;
398 /* make sure all the rest is digits */
399 for (p
= end
+ 1; *p
; p
++) if (!isdigit(*p
)) return;
403 /*******************************************************************
406 * Parse an ordinal definition.
408 static void ParseOrdinal(int ordinal
)
412 ORDDEF
*odp
= xmalloc( sizeof(*odp
) );
413 memset( odp
, 0, sizeof(*odp
) );
414 EntryPoints
[nb_entry_points
++] = odp
;
418 for (odp
->type
= 0; odp
->type
< TYPE_NBTYPES
; odp
->type
++)
419 if (TypeNames
[odp
->type
] && !strcmp( token
, TypeNames
[odp
->type
] ))
422 if (odp
->type
>= TYPE_NBTYPES
)
423 fatal_error( "Expected type after ordinal, found '%s' instead\n", token
);
426 if (*token
== '-') token
= ParseFlags( odp
);
428 odp
->name
= xstrdup( token
);
429 fix_export_name( odp
->name
);
430 odp
->lineno
= current_line
;
431 odp
->ordinal
= ordinal
;
436 ParseVariable( odp
);
444 ParseExportFunction( odp
);
447 ParseInterrupt( odp
);
466 if (odp
->flags
& FLAG_I386
)
468 /* ignore this entry point on non-Intel archs */
469 EntryPoints
[--nb_entry_points
] = NULL
;
477 if (ordinal
>= MAX_ORDINALS
) fatal_error( "Ordinal number %d too large\n", ordinal
);
478 if (ordinal
> Limit
) Limit
= ordinal
;
479 if (ordinal
< Base
) Base
= ordinal
;
480 odp
->ordinal
= ordinal
;
481 Ordinals
[ordinal
] = odp
;
484 if (!strcmp( odp
->name
, "@" ))
487 fatal_error( "Nameless function needs an explicit ordinal number\n" );
488 if (SpecType
!= SPEC_WIN32
)
489 fatal_error( "Nameless functions not supported for Win16\n" );
492 else Names
[nb_names
++] = odp
;
496 static int name_compare( const void *name1
, const void *name2
)
498 ORDDEF
*odp1
= *(ORDDEF
**)name1
;
499 ORDDEF
*odp2
= *(ORDDEF
**)name2
;
500 return strcmp( odp1
->name
, odp2
->name
);
503 /*******************************************************************
506 * Sort the name array and catch duplicates.
508 static void sort_names(void)
512 if (!nb_names
) return;
514 /* sort the list of names */
515 qsort( Names
, nb_names
, sizeof(Names
[0]), name_compare
);
517 /* check for duplicate names */
518 for (i
= 0; i
< nb_names
- 1; i
++)
520 if (!strcmp( Names
[i
]->name
, Names
[i
+1]->name
))
522 current_line
= max( Names
[i
]->lineno
, Names
[i
+1]->lineno
);
523 fatal_error( "'%s' redefined (previous definition at line %d)\n",
524 Names
[i
]->name
, min( Names
[i
]->lineno
, Names
[i
+1]->lineno
) );
530 /*******************************************************************
535 SPEC_TYPE
ParseTopLevel( FILE *file
)
541 while ((token
= GetToken(1)) != NULL
)
543 if (strcmp(token
, "name") == 0)
545 strcpy(DLLName
, GetToken(0));
547 else if (strcmp(token
, "file") == 0)
549 strcpy(DLLFileName
, GetToken(0));
550 strupper(DLLFileName
);
552 else if (strcmp(token
, "type") == 0)
555 if (!strcmp(token
, "win16" )) SpecType
= SPEC_WIN16
;
556 else if (!strcmp(token
, "win32" )) SpecType
= SPEC_WIN32
;
557 else fatal_error( "Type must be 'win16' or 'win32'\n" );
559 else if (strcmp(token
, "mode") == 0)
562 if (!strcmp(token
, "dll" )) SpecMode
= SPEC_MODE_DLL
;
563 else if (!strcmp(token
, "guiexe" )) SpecMode
= SPEC_MODE_GUIEXE
;
564 else if (!strcmp(token
, "cuiexe" )) SpecMode
= SPEC_MODE_CUIEXE
;
565 else if (!strcmp(token
, "guiexe_unicode" )) SpecMode
= SPEC_MODE_GUIEXE_UNICODE
;
566 else if (!strcmp(token
, "cuiexe_unicode" )) SpecMode
= SPEC_MODE_CUIEXE_UNICODE
;
567 else fatal_error( "Mode must be 'dll', 'guiexe', 'cuiexe', 'guiexe_unicode' or 'cuiexe_unicode'\n" );
569 else if (strcmp(token
, "heap") == 0)
572 if (!IsNumberString(token
)) fatal_error( "Expected number after heap\n" );
573 DLLHeapSize
= atoi(token
);
575 else if (strcmp(token
, "init") == 0)
577 if (SpecType
== SPEC_WIN16
)
578 fatal_error( "init cannot be used for Win16 spec files\n" );
579 init_func
= xstrdup( GetToken(0) );
581 else if (strcmp(token
, "import") == 0)
586 if (SpecType
!= SPEC_WIN32
)
587 fatal_error( "Imports not supported for Win16\n" );
592 if (!strcmp(name
, "delay"))
599 warning( "The 'delay' option is not yet supported on the PPC. 'delay' will be ignored.\n");
602 else fatal_error( "Unknown option '%s' for import directive\n", name
);
604 add_import_dll( name
, delay
);
606 else if (strcmp(token
, "rsrc") == 0)
608 if (SpecType
!= SPEC_WIN16
) load_res32_file( GetToken(0) );
609 else load_res16_file( GetToken(0) );
611 else if (strcmp(token
, "owner") == 0)
613 if (SpecType
!= SPEC_WIN16
)
614 fatal_error( "Owner only supported for Win16 spec files\n" );
615 strcpy( owner_name
, GetToken(0) );
617 else if (strcmp(token
, "debug_channels") == 0)
619 if (SpecType
!= SPEC_WIN32
)
620 fatal_error( "debug channels only supported for Win32 spec files\n" );
623 else if (strcmp(token
, "ignore") == 0)
625 if (SpecType
!= SPEC_WIN32
)
626 fatal_error( "'ignore' only supported for Win32 spec files\n" );
629 else if (strcmp(token
, "@") == 0)
631 if (SpecType
!= SPEC_WIN32
)
632 fatal_error( "'@' ordinals not supported for Win16\n" );
635 else if (IsNumberString(token
))
637 ParseOrdinal( atoi(token
) );
640 fatal_error( "Expected name, id, length or ordinal\n" );
645 if (SpecMode
== SPEC_MODE_DLL
)
646 sprintf( DLLFileName
, "%s.dll", DLLName
);
648 sprintf( DLLFileName
, "%s.exe", DLLName
);
651 if (SpecType
== SPEC_INVALID
) fatal_error( "Missing 'type' declaration\n" );
652 if (SpecType
== SPEC_WIN16
&& !owner_name
[0])
653 fatal_error( "'owner' not specified for Win16 dll\n" );
655 current_line
= 0; /* no longer parsing the input file */