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 TokenBuffer
[512];
28 static char *ParseNext
= ParseBuffer
;
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(const 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 const char * GetTokenInLine(void)
70 char *token
= TokenBuffer
;
73 * Remove initial white space.
75 while (isspace(*p
)) p
++;
77 if ((*p
== '\0') || (*p
== '#')) return NULL
;
82 if (is_token_separator(*p
))
84 /* a separator is always a complete token */
87 else while (*p
!= '\0' && !is_token_separator(*p
) && !isspace(*p
))
90 if (*p
) *token
++ = *p
++;
97 static const char * GetToken( int allow_eof
)
101 while ((token
= GetTokenInLine()) == NULL
)
103 ParseNext
= ParseBuffer
;
105 if (fgets(ParseBuffer
, sizeof(ParseBuffer
), input_file
) == NULL
)
107 if (!allow_eof
) fatal_error( "Unexpected end of file\n" );
115 /*******************************************************************
118 * Parse a debug channel definition.
120 static void ParseDebug(void)
122 const char *token
= GetToken(0);
123 if (*token
!= '(') fatal_error( "Expected '(' got '%s'\n", token
);
127 if (*token
== ')') break;
128 debug_channels
= xrealloc( debug_channels
,
129 (nb_debug_channels
+ 1) * sizeof(*debug_channels
));
130 debug_channels
[nb_debug_channels
++] = xstrdup(token
);
135 /*******************************************************************
138 * Parse an 'ignore' definition.
140 static void ParseIgnore(void)
142 const char *token
= GetToken(0);
143 if (*token
!= '(') fatal_error( "Expected '(' got '%s'\n", token
);
147 if (*token
== ')') break;
148 add_ignore_symbol( token
);
153 /*******************************************************************
156 * Parse a variable definition.
158 static void ParseVariable( ORDDEF
*odp
)
163 int value_array_size
;
165 const char *token
= GetToken(0);
166 if (*token
!= '(') fatal_error( "Expected '(' got '%s'\n", token
);
169 value_array_size
= 25;
170 value_array
= xmalloc(sizeof(*value_array
) * value_array_size
);
178 value_array
[n_values
++] = strtol(token
, &endptr
, 0);
179 if (n_values
== value_array_size
)
181 value_array_size
+= 25;
182 value_array
= xrealloc(value_array
,
183 sizeof(*value_array
) * value_array_size
);
186 if (endptr
== NULL
|| *endptr
!= '\0')
187 fatal_error( "Expected number value, got '%s'\n", token
);
190 odp
->u
.var
.n_values
= n_values
;
191 odp
->u
.var
.values
= xrealloc(value_array
, sizeof(*value_array
) * n_values
);
195 /*******************************************************************
196 * ParseExportFunction
198 * Parse a function definition.
200 static void ParseExportFunction( ORDDEF
*odp
)
208 if (odp
->type
== TYPE_STDCALL
)
209 fatal_error( "'stdcall' not supported for Win16\n" );
210 if (odp
->type
== TYPE_VARARGS
)
211 fatal_error( "'varargs' not supported for Win16\n" );
214 if ((odp
->type
== TYPE_PASCAL
) || (odp
->type
== TYPE_PASCAL_16
))
215 fatal_error( "'pascal' not supported for Win32\n" );
222 if (*token
!= '(') fatal_error( "Expected '(' got '%s'\n", token
);
224 for (i
= 0; i
< sizeof(odp
->u
.func
.arg_types
); i
++)
230 if (!strcmp(token
, "word"))
231 odp
->u
.func
.arg_types
[i
] = 'w';
232 else if (!strcmp(token
, "s_word"))
233 odp
->u
.func
.arg_types
[i
] = 's';
234 else if (!strcmp(token
, "long") || !strcmp(token
, "segptr"))
235 odp
->u
.func
.arg_types
[i
] = 'l';
236 else if (!strcmp(token
, "ptr"))
237 odp
->u
.func
.arg_types
[i
] = 'p';
238 else if (!strcmp(token
, "str"))
239 odp
->u
.func
.arg_types
[i
] = 't';
240 else if (!strcmp(token
, "wstr"))
241 odp
->u
.func
.arg_types
[i
] = 'W';
242 else if (!strcmp(token
, "segstr"))
243 odp
->u
.func
.arg_types
[i
] = 'T';
244 else if (!strcmp(token
, "double"))
246 odp
->u
.func
.arg_types
[i
++] = 'l';
247 if (i
< sizeof(odp
->u
.func
.arg_types
)) odp
->u
.func
.arg_types
[i
] = 'l';
249 else fatal_error( "Unknown variable type '%s'\n", token
);
251 if (SpecType
== SPEC_WIN32
)
253 if (strcmp(token
, "long") &&
254 strcmp(token
, "ptr") &&
255 strcmp(token
, "str") &&
256 strcmp(token
, "wstr") &&
257 strcmp(token
, "double"))
259 fatal_error( "Type '%s' not supported for Win32\n", token
);
263 if ((*token
!= ')') || (i
>= sizeof(odp
->u
.func
.arg_types
)))
264 fatal_error( "Too many arguments\n" );
266 odp
->u
.func
.arg_types
[i
] = '\0';
267 if ((odp
->type
== TYPE_STDCALL
) && !i
)
268 odp
->type
= TYPE_CDECL
; /* stdcall is the same as cdecl for 0 args */
269 if (odp
->type
== TYPE_VARARGS
)
270 odp
->flags
|= FLAG_NORELAY
; /* no relay debug possible for varags entry point */
271 odp
->link_name
= xstrdup( GetToken(0) );
275 /*******************************************************************
278 * Parse an 'equate' definition.
280 static void ParseEquate( ORDDEF
*odp
)
284 const char *token
= GetToken(0);
285 int value
= strtol(token
, &endptr
, 0);
286 if (endptr
== NULL
|| *endptr
!= '\0')
287 fatal_error( "Expected number value, got '%s'\n", token
);
288 if (SpecType
== SPEC_WIN32
)
289 fatal_error( "'equate' not supported for Win32\n" );
290 odp
->u
.abs
.value
= value
;
294 /*******************************************************************
297 * Parse a 'stub' definition.
299 static void ParseStub( ORDDEF
*odp
)
301 odp
->u
.func
.arg_types
[0] = '\0';
302 odp
->link_name
= xstrdup("");
306 /*******************************************************************
309 * Parse an 'interrupt' definition.
311 static void ParseInterrupt( ORDDEF
*odp
)
315 if (SpecType
== SPEC_WIN32
)
316 fatal_error( "'interrupt' not supported for Win32\n" );
319 if (*token
!= '(') fatal_error( "Expected '(' got '%s'\n", token
);
322 if (*token
!= ')') fatal_error( "Expected ')' got '%s'\n", token
);
324 odp
->u
.func
.arg_types
[0] = '\0';
325 odp
->link_name
= xstrdup( GetToken(0) );
329 /*******************************************************************
332 * Parse an 'extern' definition.
334 static void ParseExtern( ORDDEF
*odp
)
336 if (SpecType
== SPEC_WIN16
) fatal_error( "'extern' not supported for Win16\n" );
337 odp
->link_name
= xstrdup( GetToken(0) );
338 /* 'extern' definitions are not available for implicit import */
339 odp
->flags
|= FLAG_NOIMPORT
;
343 /*******************************************************************
346 * Parse a 'forward' definition.
348 static void ParseForward( ORDDEF
*odp
)
350 if (SpecType
== SPEC_WIN16
) fatal_error( "'forward' not supported for Win16\n" );
351 odp
->link_name
= xstrdup( GetToken(0) );
355 /*******************************************************************
358 * Parse the optional flags for an entry point
360 static const char *ParseFlags( ORDDEF
*odp
)
368 for (i
= 0; FlagNames
[i
]; i
++)
369 if (!strcmp( FlagNames
[i
], token
)) break;
370 if (!FlagNames
[i
]) fatal_error( "Unknown flag '%s'\n", token
);
371 odp
->flags
|= 1 << i
;
373 } while (*token
== '-');
378 /*******************************************************************
381 * Fix an exported function name by removing a possible @xx suffix
383 static void fix_export_name( char *name
)
385 char *p
, *end
= strrchr( name
, '@' );
386 if (!end
|| !end
[1] || end
== name
) return;
387 /* make sure all the rest is digits */
388 for (p
= end
+ 1; *p
; p
++) if (!isdigit(*p
)) return;
392 /*******************************************************************
395 * Parse an ordinal definition.
397 static void ParseOrdinal(int ordinal
)
401 ORDDEF
*odp
= xmalloc( sizeof(*odp
) );
402 memset( odp
, 0, sizeof(*odp
) );
403 EntryPoints
[nb_entry_points
++] = odp
;
407 for (odp
->type
= 0; odp
->type
< TYPE_NBTYPES
; odp
->type
++)
408 if (TypeNames
[odp
->type
] && !strcmp( token
, TypeNames
[odp
->type
] ))
411 if (odp
->type
>= TYPE_NBTYPES
)
412 fatal_error( "Expected type after ordinal, found '%s' instead\n", token
);
415 if (*token
== '-') token
= ParseFlags( odp
);
417 odp
->name
= xstrdup( token
);
418 fix_export_name( odp
->name
);
419 odp
->lineno
= current_line
;
420 odp
->ordinal
= ordinal
;
425 ParseVariable( odp
);
433 ParseExportFunction( odp
);
436 ParseInterrupt( odp
);
455 if (odp
->flags
& FLAG_I386
)
457 /* ignore this entry point on non-Intel archs */
458 EntryPoints
[--nb_entry_points
] = NULL
;
466 if (ordinal
>= MAX_ORDINALS
) fatal_error( "Ordinal number %d too large\n", ordinal
);
467 if (ordinal
> Limit
) Limit
= ordinal
;
468 if (ordinal
< Base
) Base
= ordinal
;
469 odp
->ordinal
= ordinal
;
470 Ordinals
[ordinal
] = odp
;
473 if (!strcmp( odp
->name
, "@" ))
476 fatal_error( "Nameless function needs an explicit ordinal number\n" );
477 if (SpecType
!= SPEC_WIN32
)
478 fatal_error( "Nameless functions not supported for Win16\n" );
481 else Names
[nb_names
++] = odp
;
485 static int name_compare( const void *name1
, const void *name2
)
487 ORDDEF
*odp1
= *(ORDDEF
**)name1
;
488 ORDDEF
*odp2
= *(ORDDEF
**)name2
;
489 return strcmp( odp1
->name
, odp2
->name
);
492 /*******************************************************************
495 * Sort the name array and catch duplicates.
497 static void sort_names(void)
501 if (!nb_names
) return;
503 /* sort the list of names */
504 qsort( Names
, nb_names
, sizeof(Names
[0]), name_compare
);
506 /* check for duplicate names */
507 for (i
= 0; i
< nb_names
- 1; i
++)
509 if (!strcmp( Names
[i
]->name
, Names
[i
+1]->name
))
511 current_line
= max( Names
[i
]->lineno
, Names
[i
+1]->lineno
);
512 fatal_error( "'%s' redefined (previous definition at line %d)\n",
513 Names
[i
]->name
, min( Names
[i
]->lineno
, Names
[i
+1]->lineno
) );
519 /*******************************************************************
524 SPEC_TYPE
ParseTopLevel( FILE *file
)
530 while ((token
= GetToken(1)) != NULL
)
532 if (strcmp(token
, "name") == 0)
534 strcpy(DLLName
, GetToken(0));
536 else if (strcmp(token
, "file") == 0)
538 strcpy(DLLFileName
, GetToken(0));
539 strupper(DLLFileName
);
541 else if (strcmp(token
, "type") == 0)
544 if (!strcmp(token
, "win16" )) SpecType
= SPEC_WIN16
;
545 else if (!strcmp(token
, "win32" )) SpecType
= SPEC_WIN32
;
546 else fatal_error( "Type must be 'win16' or 'win32'\n" );
548 else if (strcmp(token
, "mode") == 0)
551 if (!strcmp(token
, "dll" )) SpecMode
= SPEC_MODE_DLL
;
552 else if (!strcmp(token
, "guiexe" )) SpecMode
= SPEC_MODE_GUIEXE
;
553 else if (!strcmp(token
, "cuiexe" )) SpecMode
= SPEC_MODE_CUIEXE
;
554 else if (!strcmp(token
, "guiexe_unicode" )) SpecMode
= SPEC_MODE_GUIEXE_UNICODE
;
555 else if (!strcmp(token
, "cuiexe_unicode" )) SpecMode
= SPEC_MODE_CUIEXE_UNICODE
;
556 else fatal_error( "Mode must be 'dll', 'guiexe', 'cuiexe', 'guiexe_unicode' or 'cuiexe_unicode'\n" );
558 else if (strcmp(token
, "heap") == 0)
561 if (!IsNumberString(token
)) fatal_error( "Expected number after heap\n" );
562 DLLHeapSize
= atoi(token
);
564 else if (strcmp(token
, "init") == 0)
566 if (SpecType
== SPEC_WIN16
)
567 fatal_error( "init cannot be used for Win16 spec files\n" );
568 init_func
= xstrdup( GetToken(0) );
570 else if (strcmp(token
, "import") == 0)
575 if (SpecType
!= SPEC_WIN32
)
576 fatal_error( "Imports not supported for Win16\n" );
581 if (!strcmp(name
, "delay"))
588 warning( "The 'delay' option is not yet supported on the PPC. 'delay' will be ignored.\n");
591 else fatal_error( "Unknown option '%s' for import directive\n", name
);
593 add_import_dll( name
, delay
);
595 else if (strcmp(token
, "rsrc") == 0)
597 if (SpecType
!= SPEC_WIN16
) load_res32_file( GetToken(0) );
598 else load_res16_file( GetToken(0) );
600 else if (strcmp(token
, "owner") == 0)
602 if (SpecType
!= SPEC_WIN16
)
603 fatal_error( "Owner only supported for Win16 spec files\n" );
604 strcpy( owner_name
, GetToken(0) );
606 else if (strcmp(token
, "debug_channels") == 0)
608 if (SpecType
!= SPEC_WIN32
)
609 fatal_error( "debug channels only supported for Win32 spec files\n" );
612 else if (strcmp(token
, "ignore") == 0)
614 if (SpecType
!= SPEC_WIN32
)
615 fatal_error( "'ignore' only supported for Win32 spec files\n" );
618 else if (strcmp(token
, "@") == 0)
620 if (SpecType
!= SPEC_WIN32
)
621 fatal_error( "'@' ordinals not supported for Win16\n" );
624 else if (IsNumberString(token
))
626 ParseOrdinal( atoi(token
) );
629 fatal_error( "Expected name, id, length or ordinal\n" );
634 if (SpecMode
== SPEC_MODE_DLL
)
635 sprintf( DLLFileName
, "%s.dll", DLLName
);
637 sprintf( DLLFileName
, "%s.exe", DLLName
);
640 if (SpecType
== SPEC_INVALID
) fatal_error( "Missing 'type' declaration\n" );
641 if (SpecType
== SPEC_WIN16
&& !owner_name
[0])
642 fatal_error( "'owner' not specified for Win16 dll\n" );
644 current_line
= 0; /* no longer parsing the input file */