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 "ret64", /* FLAG_RET64 */
65 "i386", /* FLAG_I386 */
66 "register", /* FLAG_REGISTER */
67 "interrupt", /* FLAG_INTERRUPT */
71 static int IsNumberString(const char *s
)
73 while (*s
) if (!isdigit(*s
++)) return 0;
77 inline static int is_token_separator( char ch
)
79 return (ch
== '(' || ch
== ')' || ch
== '-');
82 static const char * GetTokenInLine(void)
85 char *token
= TokenBuffer
;
88 * Remove initial white space.
90 while (isspace(*p
)) p
++;
92 if ((*p
== '\0') || (*p
== '#')) return NULL
;
97 if (is_token_separator(*p
))
99 /* a separator is always a complete token */
102 else while (*p
!= '\0' && !is_token_separator(*p
) && !isspace(*p
))
105 if (*p
) *token
++ = *p
++;
112 static const char * GetToken( int allow_eof
)
116 while ((token
= GetTokenInLine()) == NULL
)
118 ParseNext
= ParseBuffer
;
120 if (fgets(ParseBuffer
, sizeof(ParseBuffer
), input_file
) == NULL
)
122 if (!allow_eof
) fatal_error( "Unexpected end of file\n" );
130 /*******************************************************************
133 * Parse an 'ignore' definition.
135 static void ParseIgnore(void)
137 const char *token
= GetToken(0);
138 if (*token
!= '(') fatal_error( "Expected '(' got '%s'\n", token
);
142 if (*token
== ')') break;
143 add_ignore_symbol( token
);
148 /*******************************************************************
151 * Parse a variable definition.
153 static void ParseVariable( ORDDEF
*odp
)
158 int value_array_size
;
160 const char *token
= GetToken(0);
161 if (*token
!= '(') fatal_error( "Expected '(' got '%s'\n", token
);
164 value_array_size
= 25;
165 value_array
= xmalloc(sizeof(*value_array
) * value_array_size
);
173 value_array
[n_values
++] = strtol(token
, &endptr
, 0);
174 if (n_values
== value_array_size
)
176 value_array_size
+= 25;
177 value_array
= xrealloc(value_array
,
178 sizeof(*value_array
) * value_array_size
);
181 if (endptr
== NULL
|| *endptr
!= '\0')
182 fatal_error( "Expected number value, got '%s'\n", token
);
185 odp
->u
.var
.n_values
= n_values
;
186 odp
->u
.var
.values
= xrealloc(value_array
, sizeof(*value_array
) * n_values
);
190 /*******************************************************************
191 * ParseExportFunction
193 * Parse a function definition.
195 static void ParseExportFunction( ORDDEF
*odp
)
203 if (odp
->type
== TYPE_STDCALL
)
204 fatal_error( "'stdcall' not supported for Win16\n" );
205 if (odp
->type
== TYPE_VARARGS
)
206 fatal_error( "'varargs' not supported for Win16\n" );
209 if ((odp
->type
== TYPE_PASCAL
) || (odp
->type
== TYPE_PASCAL_16
))
210 fatal_error( "'pascal' not supported for Win32\n" );
211 if (odp
->flags
& FLAG_INTERRUPT
)
212 fatal_error( "'interrupt' not supported for Win32\n" );
219 if (*token
!= '(') fatal_error( "Expected '(' got '%s'\n", token
);
221 for (i
= 0; i
< sizeof(odp
->u
.func
.arg_types
); i
++)
227 if (!strcmp(token
, "word"))
228 odp
->u
.func
.arg_types
[i
] = 'w';
229 else if (!strcmp(token
, "s_word"))
230 odp
->u
.func
.arg_types
[i
] = 's';
231 else if (!strcmp(token
, "long") || !strcmp(token
, "segptr"))
232 odp
->u
.func
.arg_types
[i
] = 'l';
233 else if (!strcmp(token
, "ptr"))
234 odp
->u
.func
.arg_types
[i
] = 'p';
235 else if (!strcmp(token
, "str"))
236 odp
->u
.func
.arg_types
[i
] = 't';
237 else if (!strcmp(token
, "wstr"))
238 odp
->u
.func
.arg_types
[i
] = 'W';
239 else if (!strcmp(token
, "segstr"))
240 odp
->u
.func
.arg_types
[i
] = 'T';
241 else if (!strcmp(token
, "double"))
243 odp
->u
.func
.arg_types
[i
++] = 'l';
244 if (i
< sizeof(odp
->u
.func
.arg_types
)) odp
->u
.func
.arg_types
[i
] = 'l';
246 else fatal_error( "Unknown variable type '%s'\n", token
);
248 if (SpecType
== SPEC_WIN32
)
250 if (strcmp(token
, "long") &&
251 strcmp(token
, "ptr") &&
252 strcmp(token
, "str") &&
253 strcmp(token
, "wstr") &&
254 strcmp(token
, "double"))
256 fatal_error( "Type '%s' not supported for Win32\n", token
);
260 if ((*token
!= ')') || (i
>= sizeof(odp
->u
.func
.arg_types
)))
261 fatal_error( "Too many arguments\n" );
263 odp
->u
.func
.arg_types
[i
] = '\0';
264 if (odp
->type
== TYPE_VARARGS
)
265 odp
->flags
|= FLAG_NORELAY
; /* no relay debug possible for varags entry point */
266 odp
->link_name
= xstrdup( GetToken(0) );
270 /*******************************************************************
273 * Parse an 'equate' definition.
275 static void ParseEquate( ORDDEF
*odp
)
279 const char *token
= GetToken(0);
280 int value
= strtol(token
, &endptr
, 0);
281 if (endptr
== NULL
|| *endptr
!= '\0')
282 fatal_error( "Expected number value, got '%s'\n", token
);
283 if (SpecType
== SPEC_WIN32
)
284 fatal_error( "'equate' not supported for Win32\n" );
285 odp
->u
.abs
.value
= value
;
289 /*******************************************************************
292 * Parse a 'stub' definition.
294 static void ParseStub( ORDDEF
*odp
)
296 odp
->u
.func
.arg_types
[0] = '\0';
297 odp
->link_name
= xstrdup("");
301 /*******************************************************************
304 * Parse an 'extern' definition.
306 static void ParseExtern( ORDDEF
*odp
)
308 if (SpecType
== SPEC_WIN16
) fatal_error( "'extern' not supported for Win16\n" );
309 odp
->link_name
= xstrdup( GetToken(0) );
310 /* 'extern' definitions are not available for implicit import */
311 odp
->flags
|= FLAG_NOIMPORT
;
315 /*******************************************************************
318 * Parse a 'forward' definition.
320 static void ParseForward( ORDDEF
*odp
)
322 if (SpecType
== SPEC_WIN16
) fatal_error( "'forward' not supported for Win16\n" );
323 odp
->link_name
= xstrdup( GetToken(0) );
327 /*******************************************************************
330 * Parse the optional flags for an entry point
332 static const char *ParseFlags( ORDDEF
*odp
)
340 for (i
= 0; FlagNames
[i
]; i
++)
341 if (!strcmp( FlagNames
[i
], token
)) break;
342 if (!FlagNames
[i
]) fatal_error( "Unknown flag '%s'\n", token
);
343 odp
->flags
|= 1 << i
;
345 } while (*token
== '-');
350 /*******************************************************************
353 * Fix an exported function name by removing a possible @xx suffix
355 static void fix_export_name( char *name
)
357 char *p
, *end
= strrchr( name
, '@' );
358 if (!end
|| !end
[1] || end
== name
) return;
359 /* make sure all the rest is digits */
360 for (p
= end
+ 1; *p
; p
++) if (!isdigit(*p
)) return;
364 /*******************************************************************
367 * Parse an ordinal definition.
369 static void ParseOrdinal(int ordinal
)
373 ORDDEF
*odp
= xmalloc( sizeof(*odp
) );
374 memset( odp
, 0, sizeof(*odp
) );
375 EntryPoints
[nb_entry_points
++] = odp
;
379 for (odp
->type
= 0; odp
->type
< TYPE_NBTYPES
; odp
->type
++)
380 if (TypeNames
[odp
->type
] && !strcmp( token
, TypeNames
[odp
->type
] ))
383 if (odp
->type
>= TYPE_NBTYPES
)
384 fatal_error( "Expected type after ordinal, found '%s' instead\n", token
);
387 if (*token
== '-') token
= ParseFlags( odp
);
389 odp
->name
= xstrdup( token
);
390 fix_export_name( odp
->name
);
391 odp
->lineno
= current_line
;
392 odp
->ordinal
= ordinal
;
397 ParseVariable( odp
);
404 ParseExportFunction( odp
);
423 if (odp
->flags
& FLAG_I386
)
425 /* ignore this entry point on non-Intel archs */
426 EntryPoints
[--nb_entry_points
] = NULL
;
434 if (ordinal
>= MAX_ORDINALS
) fatal_error( "Ordinal number %d too large\n", ordinal
);
435 if (ordinal
> Limit
) Limit
= ordinal
;
436 if (ordinal
< Base
) Base
= ordinal
;
437 odp
->ordinal
= ordinal
;
438 Ordinals
[ordinal
] = odp
;
441 if (!strcmp( odp
->name
, "@" ))
444 fatal_error( "Nameless function needs an explicit ordinal number\n" );
445 if (SpecType
!= SPEC_WIN32
)
446 fatal_error( "Nameless functions not supported for Win16\n" );
449 else Names
[nb_names
++] = odp
;
453 static int name_compare( const void *name1
, const void *name2
)
455 ORDDEF
*odp1
= *(ORDDEF
**)name1
;
456 ORDDEF
*odp2
= *(ORDDEF
**)name2
;
457 return strcmp( odp1
->name
, odp2
->name
);
460 /*******************************************************************
463 * Sort the name array and catch duplicates.
465 static void sort_names(void)
469 if (!nb_names
) return;
471 /* sort the list of names */
472 qsort( Names
, nb_names
, sizeof(Names
[0]), name_compare
);
474 /* check for duplicate names */
475 for (i
= 0; i
< nb_names
- 1; i
++)
477 if (!strcmp( Names
[i
]->name
, Names
[i
+1]->name
))
479 current_line
= max( Names
[i
]->lineno
, Names
[i
+1]->lineno
);
480 fatal_error( "'%s' redefined (previous definition at line %d)\n",
481 Names
[i
]->name
, min( Names
[i
]->lineno
, Names
[i
+1]->lineno
) );
487 /*******************************************************************
492 SPEC_TYPE
ParseTopLevel( FILE *file
, int def_only
)
498 while ((token
= GetToken(1)) != NULL
)
500 if (strcmp(token
, "name") == 0)
502 strcpy(DLLName
, GetToken(0));
504 else if (strcmp(token
, "file") == 0)
506 strcpy(DLLFileName
, GetToken(0));
508 else if (strcmp(token
, "type") == 0)
511 if (!strcmp(token
, "win16" )) SpecType
= SPEC_WIN16
;
512 else if (!strcmp(token
, "win32" )) SpecType
= SPEC_WIN32
;
513 else fatal_error( "Type must be 'win16' or 'win32'\n" );
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
, "stack") == 0)
534 if (!IsNumberString(token
)) fatal_error( "Expected number after stack\n" );
535 stack_size
= atoi(token
);
537 else if (strcmp(token
, "init") == 0)
539 if (SpecType
== SPEC_WIN16
)
540 fatal_error( "init cannot be used for Win16 spec files\n" );
541 init_func
= xstrdup( GetToken(0) );
543 else if (strcmp(token
, "rsrc") == 0)
547 if (SpecType
!= SPEC_WIN16
) load_res32_file( GetToken(0) );
548 else load_res16_file( GetToken(0) );
550 else GetToken(0); /* skip it */
552 else if (strcmp(token
, "owner") == 0)
554 if (SpecType
!= SPEC_WIN16
)
555 fatal_error( "Owner only supported for Win16 spec files\n" );
556 strcpy( owner_name
, GetToken(0) );
558 else if (strcmp(token
, "ignore") == 0)
560 if (SpecType
!= SPEC_WIN32
)
561 fatal_error( "'ignore' only supported for Win32 spec files\n" );
564 else if (strcmp(token
, "@") == 0)
566 if (SpecType
!= SPEC_WIN32
)
567 fatal_error( "'@' ordinals not supported for Win16\n" );
570 else if (IsNumberString(token
))
572 ParseOrdinal( atoi(token
) );
575 fatal_error( "Expected name, id, length or ordinal\n" );
580 if (SpecMode
== SPEC_MODE_DLL
)
582 strcpy( DLLFileName
, DLLName
);
583 /* Append .dll to name if no extension present */
584 if (!strrchr( DLLFileName
, '.'))
585 strcat( DLLFileName
, ".dll" );
588 sprintf( DLLFileName
, "%s.exe", DLLName
);
591 if (SpecType
== SPEC_WIN16
&& !owner_name
[0])
592 fatal_error( "'owner' not specified for Win16 dll\n" );
594 current_line
= 0; /* no longer parsing the input file */
600 /*******************************************************************
603 static void add_debug_channel( const char *name
)
607 for (i
= 0; i
< nb_debug_channels
; i
++)
608 if (!strcmp( debug_channels
[i
], name
)) return;
610 debug_channels
= xrealloc( debug_channels
, (nb_debug_channels
+ 1) * sizeof(*debug_channels
));
611 debug_channels
[nb_debug_channels
++] = xstrdup(name
);
615 /*******************************************************************
616 * parse_debug_channels
618 * Parse a source file and extract the debug channel definitions.
620 void parse_debug_channels( const char *srcdir
, const char *filename
)
624 char *fullname
= NULL
;
628 fullname
= xmalloc( strlen(srcdir
) + strlen(filename
) + 2 );
629 strcpy( fullname
, srcdir
);
630 strcat( fullname
, "/" );
631 strcat( fullname
, filename
);
633 else fullname
= xstrdup( filename
);
635 if (!(file
= fopen( fullname
, "r" ))) fatal_error( "Cannot open file '%s'\n", fullname
);
636 input_file_name
= fullname
;
638 while (fgets( ParseBuffer
, sizeof(ParseBuffer
), file
))
640 char *channel
, *end
, *p
= ParseBuffer
;
642 p
= ParseBuffer
+ strlen(ParseBuffer
) - 1;
643 if (!eol_seen
) /* continuation line */
645 eol_seen
= (*p
== '\n');
648 if ((eol_seen
= (*p
== '\n'))) *p
= 0;
651 while (isspace(*p
)) p
++;
652 if (!memcmp( p
, "WINE_DECLARE_DEBUG_CHANNEL", 26 ) ||
653 !memcmp( p
, "WINE_DEFAULT_DEBUG_CHANNEL", 26 ))
656 while (isspace(*p
)) p
++;
658 fatal_error( "invalid debug channel specification '%s'\n", ParseBuffer
);
660 while (isspace(*p
)) p
++;
662 fatal_error( "invalid debug channel specification '%s'\n", ParseBuffer
);
664 while (isalnum(*p
) || *p
== '_') p
++;
666 while (isspace(*p
)) p
++;
668 fatal_error( "invalid debug channel specification '%s'\n", ParseBuffer
);
670 add_debug_channel( channel
);
675 input_file_name
= NULL
;