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
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "wine/port.h"
39 static SPEC_TYPE SpecType
= SPEC_WIN32
;
41 static char ParseBuffer
[512];
42 static char TokenBuffer
[512];
43 static char *ParseNext
= ParseBuffer
;
44 static FILE *input_file
;
46 static const char * const TypeNames
[TYPE_NBTYPES
] =
48 "variable", /* TYPE_VARIABLE */
49 "pascal16", /* TYPE_PASCAL_16 */
50 "pascal", /* TYPE_PASCAL */
51 "equate", /* TYPE_ABS */
52 "stub", /* TYPE_STUB */
53 "stdcall", /* TYPE_STDCALL */
54 "cdecl", /* TYPE_CDECL */
55 "varargs", /* TYPE_VARARGS */
56 "extern", /* TYPE_EXTERN */
57 "forward" /* TYPE_FORWARD */
60 static const char * const FlagNames
[] =
62 "noimport", /* FLAG_NOIMPORT */
63 "norelay", /* FLAG_NORELAY */
64 "noname", /* FLAG_NONAME */
65 "ret64", /* FLAG_RET64 */
66 "i386", /* FLAG_I386 */
67 "register", /* FLAG_REGISTER */
68 "interrupt", /* FLAG_INTERRUPT */
72 static int IsNumberString(const char *s
)
74 while (*s
) if (!isdigit(*s
++)) return 0;
78 inline static int is_token_separator( char ch
)
80 return (ch
== '(' || ch
== ')' || ch
== '-');
83 static const char * GetTokenInLine(void)
86 char *token
= TokenBuffer
;
89 * Remove initial white space.
91 while (isspace(*p
)) p
++;
93 if ((*p
== '\0') || (*p
== '#')) return NULL
;
98 if (is_token_separator(*p
))
100 /* a separator is always a complete token */
103 else while (*p
!= '\0' && !is_token_separator(*p
) && !isspace(*p
))
106 if (*p
) *token
++ = *p
++;
113 static const char * GetToken( int allow_eof
)
117 while ((token
= GetTokenInLine()) == NULL
)
119 ParseNext
= ParseBuffer
;
121 if (fgets(ParseBuffer
, sizeof(ParseBuffer
), input_file
) == NULL
)
123 if (!allow_eof
) fatal_error( "Unexpected end of file\n" );
131 /*******************************************************************
134 * Parse an 'ignore' definition.
136 static void ParseIgnore(void)
138 const char *token
= GetToken(0);
139 if (*token
!= '(') fatal_error( "Expected '(' got '%s'\n", token
);
143 if (*token
== ')') break;
144 add_ignore_symbol( token
);
149 /*******************************************************************
152 * Parse a variable definition.
154 static void ParseVariable( ORDDEF
*odp
)
159 int value_array_size
;
161 const char *token
= GetToken(0);
162 if (*token
!= '(') fatal_error( "Expected '(' got '%s'\n", token
);
165 value_array_size
= 25;
166 value_array
= xmalloc(sizeof(*value_array
) * value_array_size
);
174 value_array
[n_values
++] = strtol(token
, &endptr
, 0);
175 if (n_values
== value_array_size
)
177 value_array_size
+= 25;
178 value_array
= xrealloc(value_array
,
179 sizeof(*value_array
) * value_array_size
);
182 if (endptr
== NULL
|| *endptr
!= '\0')
183 fatal_error( "Expected number value, got '%s'\n", token
);
186 odp
->u
.var
.n_values
= n_values
;
187 odp
->u
.var
.values
= xrealloc(value_array
, sizeof(*value_array
) * n_values
);
191 /*******************************************************************
192 * ParseExportFunction
194 * Parse a function definition.
196 static void ParseExportFunction( ORDDEF
*odp
)
204 if (odp
->type
== TYPE_STDCALL
)
205 fatal_error( "'stdcall' not supported for Win16\n" );
206 if (odp
->type
== TYPE_VARARGS
)
207 fatal_error( "'varargs' not supported for Win16\n" );
210 if ((odp
->type
== TYPE_PASCAL
) || (odp
->type
== TYPE_PASCAL_16
))
211 fatal_error( "'pascal' not supported for Win32\n" );
212 if (odp
->flags
& FLAG_INTERRUPT
)
213 fatal_error( "'interrupt' not supported for Win32\n" );
220 if (*token
!= '(') fatal_error( "Expected '(' got '%s'\n", token
);
222 for (i
= 0; i
< sizeof(odp
->u
.func
.arg_types
); i
++)
228 if (!strcmp(token
, "word"))
229 odp
->u
.func
.arg_types
[i
] = 'w';
230 else if (!strcmp(token
, "s_word"))
231 odp
->u
.func
.arg_types
[i
] = 's';
232 else if (!strcmp(token
, "long") || !strcmp(token
, "segptr"))
233 odp
->u
.func
.arg_types
[i
] = 'l';
234 else if (!strcmp(token
, "ptr"))
235 odp
->u
.func
.arg_types
[i
] = 'p';
236 else if (!strcmp(token
, "str"))
237 odp
->u
.func
.arg_types
[i
] = 't';
238 else if (!strcmp(token
, "wstr"))
239 odp
->u
.func
.arg_types
[i
] = 'W';
240 else if (!strcmp(token
, "segstr"))
241 odp
->u
.func
.arg_types
[i
] = 'T';
242 else if (!strcmp(token
, "double"))
244 odp
->u
.func
.arg_types
[i
++] = 'l';
245 if (i
< sizeof(odp
->u
.func
.arg_types
)) odp
->u
.func
.arg_types
[i
] = 'l';
247 else fatal_error( "Unknown variable type '%s'\n", token
);
249 if (SpecType
== SPEC_WIN32
)
251 if (strcmp(token
, "long") &&
252 strcmp(token
, "ptr") &&
253 strcmp(token
, "str") &&
254 strcmp(token
, "wstr") &&
255 strcmp(token
, "double"))
257 fatal_error( "Type '%s' not supported for Win32\n", token
);
261 if ((*token
!= ')') || (i
>= sizeof(odp
->u
.func
.arg_types
)))
262 fatal_error( "Too many arguments\n" );
264 odp
->u
.func
.arg_types
[i
] = '\0';
265 if (odp
->type
== TYPE_VARARGS
)
266 odp
->flags
|= FLAG_NORELAY
; /* no relay debug possible for varags entry point */
267 odp
->link_name
= xstrdup( GetToken(0) );
271 /*******************************************************************
274 * Parse an 'equate' definition.
276 static void ParseEquate( ORDDEF
*odp
)
280 const char *token
= GetToken(0);
281 int value
= strtol(token
, &endptr
, 0);
282 if (endptr
== NULL
|| *endptr
!= '\0')
283 fatal_error( "Expected number value, got '%s'\n", token
);
284 if (SpecType
== SPEC_WIN32
)
285 fatal_error( "'equate' not supported for Win32\n" );
286 odp
->u
.abs
.value
= value
;
290 /*******************************************************************
293 * Parse a 'stub' definition.
295 static void ParseStub( ORDDEF
*odp
)
297 odp
->u
.func
.arg_types
[0] = '\0';
298 odp
->link_name
= xstrdup("");
302 /*******************************************************************
305 * Parse an 'extern' definition.
307 static void ParseExtern( ORDDEF
*odp
)
309 if (SpecType
== SPEC_WIN16
) fatal_error( "'extern' not supported for Win16\n" );
310 odp
->link_name
= xstrdup( GetToken(0) );
311 /* 'extern' definitions are not available for implicit import */
312 odp
->flags
|= FLAG_NOIMPORT
;
316 /*******************************************************************
319 * Parse a 'forward' definition.
321 static void ParseForward( ORDDEF
*odp
)
323 if (SpecType
== SPEC_WIN16
) fatal_error( "'forward' not supported for Win16\n" );
324 odp
->link_name
= xstrdup( GetToken(0) );
328 /*******************************************************************
331 * Parse the optional flags for an entry point
333 static const char *ParseFlags( ORDDEF
*odp
)
341 for (i
= 0; FlagNames
[i
]; i
++)
342 if (!strcmp( FlagNames
[i
], token
)) break;
343 if (!FlagNames
[i
]) fatal_error( "Unknown flag '%s'\n", token
);
344 odp
->flags
|= 1 << i
;
346 } while (*token
== '-');
351 /*******************************************************************
354 * Fix an exported function name by removing a possible @xx suffix
356 static void fix_export_name( char *name
)
358 char *p
, *end
= strrchr( name
, '@' );
359 if (!end
|| !end
[1] || end
== name
) return;
360 /* make sure all the rest is digits */
361 for (p
= end
+ 1; *p
; p
++) if (!isdigit(*p
)) return;
365 /*******************************************************************
368 * Parse an ordinal definition.
370 static void ParseOrdinal(int ordinal
)
374 ORDDEF
*odp
= xmalloc( sizeof(*odp
) );
375 memset( odp
, 0, sizeof(*odp
) );
376 EntryPoints
[nb_entry_points
++] = odp
;
380 for (odp
->type
= 0; odp
->type
< TYPE_NBTYPES
; odp
->type
++)
381 if (TypeNames
[odp
->type
] && !strcmp( token
, TypeNames
[odp
->type
] ))
384 if (odp
->type
>= TYPE_NBTYPES
)
385 fatal_error( "Expected type after ordinal, found '%s' instead\n", token
);
388 if (*token
== '-') token
= ParseFlags( odp
);
390 odp
->name
= xstrdup( token
);
391 fix_export_name( odp
->name
);
392 odp
->lineno
= current_line
;
393 odp
->ordinal
= ordinal
;
398 ParseVariable( odp
);
405 ParseExportFunction( odp
);
424 if (odp
->flags
& FLAG_I386
)
426 /* ignore this entry point on non-Intel archs */
427 EntryPoints
[--nb_entry_points
] = NULL
;
435 if (!ordinal
) fatal_error( "Ordinal 0 is not valid\n" );
436 if (ordinal
>= MAX_ORDINALS
) fatal_error( "Ordinal number %d too large\n", ordinal
);
437 if (ordinal
> Limit
) Limit
= ordinal
;
438 if (ordinal
< Base
) Base
= ordinal
;
439 odp
->ordinal
= ordinal
;
440 Ordinals
[ordinal
] = odp
;
443 if (!strcmp( odp
->name
, "@" ) || odp
->flags
& FLAG_NONAME
)
446 fatal_error( "Nameless function needs an explicit ordinal number\n" );
447 if (SpecType
!= SPEC_WIN32
)
448 fatal_error( "Nameless functions not supported for Win16\n" );
449 if (!strcmp( odp
->name
, "@" )) free( odp
->name
);
450 else odp
->export_name
= odp
->name
;
453 else Names
[nb_names
++] = odp
;
457 static int name_compare( const void *name1
, const void *name2
)
459 ORDDEF
*odp1
= *(ORDDEF
**)name1
;
460 ORDDEF
*odp2
= *(ORDDEF
**)name2
;
461 return strcmp( odp1
->name
, odp2
->name
);
464 /*******************************************************************
467 * Sort the name array and catch duplicates.
469 static void sort_names(void)
473 if (!nb_names
) return;
475 /* sort the list of names */
476 qsort( Names
, nb_names
, sizeof(Names
[0]), name_compare
);
478 /* check for duplicate names */
479 for (i
= 0; i
< nb_names
- 1; i
++)
481 if (!strcmp( Names
[i
]->name
, Names
[i
+1]->name
))
483 current_line
= max( Names
[i
]->lineno
, Names
[i
+1]->lineno
);
484 fatal_error( "'%s' redefined\n%s:%d: First defined here\n",
485 Names
[i
]->name
, input_file_name
,
486 min( Names
[i
]->lineno
, Names
[i
+1]->lineno
) );
492 /*******************************************************************
497 SPEC_TYPE
ParseTopLevel( FILE *file
, int def_only
)
503 if (owner_name
[0]) SpecType
= SPEC_WIN16
;
505 while ((token
= GetToken(1)) != NULL
)
507 if (strcmp(token
, "name") == 0)
509 strcpy(DLLName
, GetToken(0));
511 else if (strcmp(token
, "file") == 0)
513 strcpy(DLLFileName
, GetToken(0));
515 else if (strcmp(token
, "mode") == 0)
518 if (!strcmp(token
, "dll" )) SpecMode
= SPEC_MODE_DLL
;
519 else if (!strcmp(token
, "guiexe" )) SpecMode
= SPEC_MODE_GUIEXE
;
520 else if (!strcmp(token
, "cuiexe" )) SpecMode
= SPEC_MODE_CUIEXE
;
521 else if (!strcmp(token
, "guiexe_unicode" )) SpecMode
= SPEC_MODE_GUIEXE_UNICODE
;
522 else if (!strcmp(token
, "cuiexe_unicode" )) SpecMode
= SPEC_MODE_CUIEXE_UNICODE
;
523 else fatal_error( "Mode must be 'dll', 'guiexe', 'cuiexe', 'guiexe_unicode' or 'cuiexe_unicode'\n" );
525 else if (strcmp(token
, "heap") == 0)
528 if (!IsNumberString(token
)) fatal_error( "Expected number after heap\n" );
529 DLLHeapSize
= atoi(token
);
531 else if (strcmp(token
, "init") == 0)
533 if (SpecType
== SPEC_WIN16
)
534 fatal_error( "init cannot be used for Win16 spec files\n" );
535 init_func
= xstrdup( GetToken(0) );
537 else if (strcmp(token
, "rsrc") == 0)
541 if (SpecType
!= SPEC_WIN16
) load_res32_file( GetToken(0) );
542 else load_res16_file( GetToken(0) );
544 else GetToken(0); /* skip it */
546 else if (strcmp(token
, "ignore") == 0)
548 if (SpecType
!= SPEC_WIN32
)
549 fatal_error( "'ignore' only supported for Win32 spec files\n" );
552 else if (strcmp(token
, "@") == 0)
554 if (SpecType
!= SPEC_WIN32
)
555 fatal_error( "'@' ordinals not supported for Win16\n" );
558 else if (IsNumberString(token
))
560 ParseOrdinal( atoi(token
) );
563 fatal_error( "Expected name, id, length or ordinal\n" );
566 if (SpecType
== SPEC_WIN16
&& !owner_name
[0])
567 fatal_error( "'owner' not specified for Win16 dll\n" );
569 current_line
= 0; /* no longer parsing the input file */
575 /*******************************************************************
578 static void add_debug_channel( const char *name
)
582 for (i
= 0; i
< nb_debug_channels
; i
++)
583 if (!strcmp( debug_channels
[i
], name
)) return;
585 debug_channels
= xrealloc( debug_channels
, (nb_debug_channels
+ 1) * sizeof(*debug_channels
));
586 debug_channels
[nb_debug_channels
++] = xstrdup(name
);
590 /*******************************************************************
591 * parse_debug_channels
593 * Parse a source file and extract the debug channel definitions.
595 void parse_debug_channels( const char *srcdir
, const char *filename
)
600 file
= open_input_file( srcdir
, filename
);
601 while (fgets( ParseBuffer
, sizeof(ParseBuffer
), file
))
603 char *channel
, *end
, *p
= ParseBuffer
;
605 p
= ParseBuffer
+ strlen(ParseBuffer
) - 1;
606 if (!eol_seen
) /* continuation line */
608 eol_seen
= (*p
== '\n');
611 if ((eol_seen
= (*p
== '\n'))) *p
= 0;
614 while (isspace(*p
)) p
++;
615 if (!memcmp( p
, "WINE_DECLARE_DEBUG_CHANNEL", 26 ) ||
616 !memcmp( p
, "WINE_DEFAULT_DEBUG_CHANNEL", 26 ))
619 while (isspace(*p
)) p
++;
621 fatal_error( "invalid debug channel specification '%s'\n", ParseBuffer
);
623 while (isspace(*p
)) p
++;
625 fatal_error( "invalid debug channel specification '%s'\n", ParseBuffer
);
627 while (isalnum(*p
) || *p
== '_') p
++;
629 while (isspace(*p
)) p
++;
631 fatal_error( "invalid debug channel specification '%s'\n", ParseBuffer
);
633 add_debug_channel( channel
);
637 close_input_file( file
);