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 a variable definition.
151 static void ParseVariable( ORDDEF
*odp
)
156 int value_array_size
;
158 char *token
= GetToken(0);
159 if (*token
!= '(') fatal_error( "Expected '(' got '%s'\n", token
);
162 value_array_size
= 25;
163 value_array
= xmalloc(sizeof(*value_array
) * value_array_size
);
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
)
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" );
207 if ((odp
->type
== TYPE_PASCAL
) || (odp
->type
== TYPE_PASCAL_16
))
208 fatal_error( "'pascal' not supported for Win32\n" );
215 if (*token
!= '(') fatal_error( "Expected '(' got '%s'\n", token
);
217 for (i
= 0; i
< sizeof(odp
->u
.func
.arg_types
); i
++)
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 /*******************************************************************
271 * Parse an 'equate' definition.
273 static void ParseEquate( ORDDEF
*odp
)
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 /*******************************************************************
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 /*******************************************************************
302 * Parse an 'interrupt' definition.
304 static void ParseInterrupt( ORDDEF
*odp
)
308 if (SpecType
== SPEC_WIN32
)
309 fatal_error( "'interrupt' not supported for Win32\n" );
312 if (*token
!= '(') fatal_error( "Expected '(' got '%s'\n", token
);
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 /*******************************************************************
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 /*******************************************************************
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 /*******************************************************************
351 * Parse the optional flags for an entry point
353 static char *ParseFlags( ORDDEF
*odp
)
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
;
366 } while (*token
== '-');
371 /*******************************************************************
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;
385 /*******************************************************************
388 * Parse an ordinal definition.
390 static void ParseOrdinal(int ordinal
)
394 ORDDEF
*odp
= &EntryPoints
[nb_entry_points
++];
398 for (odp
->type
= 0; odp
->type
< TYPE_NBTYPES
; odp
->type
++)
399 if (TypeNames
[odp
->type
] && !strcmp( token
, TypeNames
[odp
->type
] ))
402 if (odp
->type
>= TYPE_NBTYPES
)
403 fatal_error( "Expected type after ordinal, found '%s' instead\n", token
);
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
;
416 ParseVariable( odp
);
424 ParseExportFunction( odp
);
427 ParseInterrupt( odp
);
446 if (odp
->flags
& FLAG_I386
)
448 /* ignore this entry point on non-Intel archs */
450 memset( odp
, 0, sizeof(*odp
) );
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
, "@" ))
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" );
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 /*******************************************************************
486 * Sort the name array and catch duplicates.
488 static void sort_names(void)
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 /*******************************************************************
515 SPEC_TYPE
ParseTopLevel( FILE *file
)
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)
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)
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)
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" );
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" );
586 else if (strcmp(token
, "@") == 0)
588 if (SpecType
!= SPEC_WIN32
)
589 fatal_error( "'@' ordinals not supported for Win16\n" );
592 else if (IsNumberString(token
))
594 ParseOrdinal( atoi(token
) );
597 fatal_error( "Expected name, id, length or ordinal\n" );
602 if (SpecMode
== SPEC_MODE_DLL
)
603 sprintf( DLLFileName
, "%s.dll", DLLName
);
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 */