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 char ParseBuffer
[512];
40 static char TokenBuffer
[512];
41 static char *ParseNext
= ParseBuffer
;
42 static FILE *input_file
;
44 static const char * const TypeNames
[TYPE_NBTYPES
] =
46 "variable", /* TYPE_VARIABLE */
47 "pascal16", /* TYPE_PASCAL_16 */
48 "pascal", /* TYPE_PASCAL */
49 "equate", /* TYPE_ABS */
50 "stub", /* TYPE_STUB */
51 "stdcall", /* TYPE_STDCALL */
52 "cdecl", /* TYPE_CDECL */
53 "varargs", /* TYPE_VARARGS */
54 "extern" /* TYPE_EXTERN */
57 static const char * const FlagNames
[] =
59 "norelay", /* FLAG_NORELAY */
60 "noname", /* FLAG_NONAME */
61 "ret64", /* FLAG_RET64 */
62 "i386", /* FLAG_I386 */
63 "register", /* FLAG_REGISTER */
64 "interrupt", /* FLAG_INTERRUPT */
65 "private", /* FLAG_PRIVATE */
69 static int IsNumberString(const char *s
)
71 while (*s
) if (!isdigit(*s
++)) return 0;
75 inline static int is_token_separator( char ch
)
77 return (ch
== '(' || ch
== ')' || ch
== '-');
80 /* get the next line from the input file, or return 0 if at eof */
81 static int get_next_line(void)
83 ParseNext
= ParseBuffer
;
85 return (fgets(ParseBuffer
, sizeof(ParseBuffer
), input_file
) != NULL
);
88 static const char * GetToken( int allow_eol
)
91 char *token
= TokenBuffer
;
95 /* remove initial white space */
97 while (isspace(*p
)) p
++;
99 if (*p
== '\\' && p
[1] == '\n') /* line continuation */
101 if (!get_next_line())
103 if (!allow_eol
) error( "Unexpected end of file\n" );
110 if ((*p
== '\0') || (*p
== '#'))
112 if (!allow_eol
) error( "Declaration not terminated properly\n" );
119 if (is_token_separator(*p
))
121 /* a separator is always a complete token */
124 else while (*p
!= '\0' && !is_token_separator(*p
) && !isspace(*p
))
127 if (*p
) *token
++ = *p
++;
135 /*******************************************************************
138 * Parse a variable definition.
140 static int ParseVariable( ORDDEF
*odp
)
145 int value_array_size
;
148 if (SpecType
== SPEC_WIN32
)
150 error( "'variable' not supported in Win32, use 'extern' instead\n" );
154 if (!(token
= GetToken(0))) return 0;
157 error( "Expected '(' got '%s'\n", token
);
162 value_array_size
= 25;
163 value_array
= xmalloc(sizeof(*value_array
) * value_array_size
);
167 if (!(token
= GetToken(0)))
175 value_array
[n_values
++] = strtol(token
, &endptr
, 0);
176 if (n_values
== value_array_size
)
178 value_array_size
+= 25;
179 value_array
= xrealloc(value_array
,
180 sizeof(*value_array
) * value_array_size
);
183 if (endptr
== NULL
|| *endptr
!= '\0')
185 error( "Expected number value, got '%s'\n", token
);
191 odp
->u
.var
.n_values
= n_values
;
192 odp
->u
.var
.values
= xrealloc(value_array
, sizeof(*value_array
) * n_values
);
197 /*******************************************************************
198 * ParseExportFunction
200 * Parse a function definition.
202 static int ParseExportFunction( ORDDEF
*odp
)
210 if (odp
->type
== TYPE_STDCALL
)
212 error( "'stdcall' not supported for Win16\n" );
215 if (odp
->type
== TYPE_VARARGS
)
217 error( "'varargs' not supported for Win16\n" );
222 if ((odp
->type
== TYPE_PASCAL
) || (odp
->type
== TYPE_PASCAL_16
))
224 error( "'pascal' not supported for Win32\n" );
227 if (odp
->flags
& FLAG_INTERRUPT
)
229 error( "'interrupt' not supported for Win32\n" );
237 if (!(token
= GetToken(0))) return 0;
240 error( "Expected '(' got '%s'\n", token
);
244 for (i
= 0; i
< sizeof(odp
->u
.func
.arg_types
); i
++)
246 if (!(token
= GetToken(0))) return 0;
250 if (!strcmp(token
, "word"))
251 odp
->u
.func
.arg_types
[i
] = 'w';
252 else if (!strcmp(token
, "s_word"))
253 odp
->u
.func
.arg_types
[i
] = 's';
254 else if (!strcmp(token
, "long") || !strcmp(token
, "segptr"))
255 odp
->u
.func
.arg_types
[i
] = 'l';
256 else if (!strcmp(token
, "ptr"))
257 odp
->u
.func
.arg_types
[i
] = 'p';
258 else if (!strcmp(token
, "str"))
259 odp
->u
.func
.arg_types
[i
] = 't';
260 else if (!strcmp(token
, "wstr"))
261 odp
->u
.func
.arg_types
[i
] = 'W';
262 else if (!strcmp(token
, "segstr"))
263 odp
->u
.func
.arg_types
[i
] = 'T';
264 else if (!strcmp(token
, "double"))
266 odp
->u
.func
.arg_types
[i
++] = 'l';
267 if (i
< sizeof(odp
->u
.func
.arg_types
)) odp
->u
.func
.arg_types
[i
] = 'l';
271 error( "Unknown argument type '%s'\n", token
);
275 if (SpecType
== SPEC_WIN32
)
277 if (strcmp(token
, "long") &&
278 strcmp(token
, "ptr") &&
279 strcmp(token
, "str") &&
280 strcmp(token
, "wstr") &&
281 strcmp(token
, "double"))
283 error( "Type '%s' not supported for Win32\n", token
);
288 if ((*token
!= ')') || (i
>= sizeof(odp
->u
.func
.arg_types
)))
290 error( "Too many arguments\n" );
294 odp
->u
.func
.arg_types
[i
] = '\0';
295 if (odp
->type
== TYPE_VARARGS
)
296 odp
->flags
|= FLAG_NORELAY
; /* no relay debug possible for varags entry point */
298 if (!(token
= GetToken(1)))
300 if (!strcmp( odp
->name
, "@" ))
302 error( "Missing handler name for anonymous function\n" );
305 odp
->link_name
= xstrdup( odp
->name
);
309 odp
->link_name
= xstrdup( token
);
310 if (strchr( odp
->link_name
, '.' ))
312 if (SpecType
== SPEC_WIN16
)
314 error( "Forwarded functions not supported for Win16\n" );
317 odp
->flags
|= FLAG_FORWARD
;
324 /*******************************************************************
327 * Parse an 'equate' definition.
329 static int ParseEquate( ORDDEF
*odp
)
335 if (SpecType
== SPEC_WIN32
)
337 error( "'equate' not supported for Win32\n" );
340 if (!(token
= GetToken(0))) return 0;
341 value
= strtol(token
, &endptr
, 0);
342 if (endptr
== NULL
|| *endptr
!= '\0')
344 error( "Expected number value, got '%s'\n", token
);
347 odp
->u
.abs
.value
= value
;
352 /*******************************************************************
355 * Parse a 'stub' definition.
357 static int ParseStub( ORDDEF
*odp
)
359 odp
->u
.func
.arg_types
[0] = '\0';
360 odp
->link_name
= xstrdup("");
365 /*******************************************************************
368 * Parse an 'extern' definition.
370 static int ParseExtern( ORDDEF
*odp
)
374 if (SpecType
== SPEC_WIN16
)
376 error( "'extern' not supported for Win16, use 'variable' instead\n" );
379 if (!(token
= GetToken(1)))
381 if (!strcmp( odp
->name
, "@" ))
383 error( "Missing handler name for anonymous extern\n" );
386 odp
->link_name
= xstrdup( odp
->name
);
390 odp
->link_name
= xstrdup( token
);
391 if (strchr( odp
->link_name
, '.' )) odp
->flags
|= FLAG_FORWARD
;
397 /*******************************************************************
400 * Parse the optional flags for an entry point
402 static const char *ParseFlags( ORDDEF
*odp
)
409 if (!(token
= GetToken(0))) break;
410 for (i
= 0; FlagNames
[i
]; i
++)
411 if (!strcmp( FlagNames
[i
], token
)) break;
414 error( "Unknown flag '%s'\n", token
);
417 odp
->flags
|= 1 << i
;
419 } while (token
&& *token
== '-');
424 /*******************************************************************
427 * Fix an exported function name by removing a possible @xx suffix
429 static void fix_export_name( char *name
)
431 char *p
, *end
= strrchr( name
, '@' );
432 if (!end
|| !end
[1] || end
== name
) return;
433 /* make sure all the rest is digits */
434 for (p
= end
+ 1; *p
; p
++) if (!isdigit(*p
)) return;
438 /*******************************************************************
441 * Parse an ordinal definition.
443 static int ParseOrdinal(int ordinal
)
447 ORDDEF
*odp
= xmalloc( sizeof(*odp
) );
448 memset( odp
, 0, sizeof(*odp
) );
449 EntryPoints
[nb_entry_points
++] = odp
;
451 if (!(token
= GetToken(0))) goto error
;
453 for (odp
->type
= 0; odp
->type
< TYPE_NBTYPES
; odp
->type
++)
454 if (TypeNames
[odp
->type
] && !strcmp( token
, TypeNames
[odp
->type
] ))
457 if (odp
->type
>= TYPE_NBTYPES
)
459 error( "Expected type after ordinal, found '%s' instead\n", token
);
463 if (!(token
= GetToken(0))) goto error
;
464 if (*token
== '-' && !(token
= ParseFlags( odp
))) goto error
;
466 odp
->name
= xstrdup( token
);
467 fix_export_name( odp
->name
);
468 odp
->lineno
= current_line
;
469 odp
->ordinal
= ordinal
;
474 if (!ParseVariable( odp
)) goto error
;
481 if (!ParseExportFunction( odp
)) goto error
;
484 if (!ParseEquate( odp
)) goto error
;
487 if (!ParseStub( odp
)) goto error
;
490 if (!ParseExtern( odp
)) goto error
;
497 if (odp
->flags
& FLAG_I386
)
499 /* ignore this entry point on non-Intel archs */
500 EntryPoints
[--nb_entry_points
] = NULL
;
510 error( "Ordinal 0 is not valid\n" );
513 if (ordinal
>= MAX_ORDINALS
)
515 error( "Ordinal number %d too large\n", ordinal
);
518 if (ordinal
> Limit
) Limit
= ordinal
;
519 if (ordinal
< Base
) Base
= ordinal
;
520 odp
->ordinal
= ordinal
;
521 if (Ordinals
[ordinal
])
523 error( "Duplicate ordinal %d\n", ordinal
);
526 Ordinals
[ordinal
] = odp
;
529 if (!strcmp( odp
->name
, "@" ) || odp
->flags
& FLAG_NONAME
)
533 error( "Nameless function needs an explicit ordinal number\n" );
536 if (SpecType
!= SPEC_WIN32
)
538 error( "Nameless functions not supported for Win16\n" );
541 if (!strcmp( odp
->name
, "@" )) free( odp
->name
);
542 else odp
->export_name
= odp
->name
;
545 else Names
[nb_names
++] = odp
;
549 EntryPoints
[--nb_entry_points
] = NULL
;
556 static int name_compare( const void *name1
, const void *name2
)
558 ORDDEF
*odp1
= *(ORDDEF
**)name1
;
559 ORDDEF
*odp2
= *(ORDDEF
**)name2
;
560 return strcmp( odp1
->name
, odp2
->name
);
563 /*******************************************************************
566 * Sort the name array and catch duplicates.
568 static void sort_names(void)
572 if (!nb_names
) return;
574 /* sort the list of names */
575 qsort( Names
, nb_names
, sizeof(Names
[0]), name_compare
);
577 /* check for duplicate names */
578 for (i
= 0; i
< nb_names
- 1; i
++)
580 if (!strcmp( Names
[i
]->name
, Names
[i
+1]->name
))
582 current_line
= max( Names
[i
]->lineno
, Names
[i
+1]->lineno
);
583 error( "'%s' redefined\n%s:%d: First defined here\n",
584 Names
[i
]->name
, input_file_name
,
585 min( Names
[i
]->lineno
, Names
[i
+1]->lineno
) );
591 /*******************************************************************
596 int ParseTopLevel( FILE *file
)
603 while (get_next_line())
605 if (!(token
= GetToken(1))) continue;
606 if (strcmp(token
, "@") == 0)
608 if (SpecType
!= SPEC_WIN32
)
610 error( "'@' ordinals not supported for Win16\n" );
613 if (!ParseOrdinal( -1 )) continue;
615 else if (IsNumberString(token
))
617 if (!ParseOrdinal( atoi(token
) )) continue;
621 error( "Expected ordinal declaration, got '%s'\n", token
);
624 if ((token
= GetToken(1))) error( "Syntax error near '%s'\n", token
);
627 current_line
= 0; /* no longer parsing the input file */
633 /*******************************************************************
636 static void add_debug_channel( const char *name
)
640 for (i
= 0; i
< nb_debug_channels
; i
++)
641 if (!strcmp( debug_channels
[i
], name
)) return;
643 debug_channels
= xrealloc( debug_channels
, (nb_debug_channels
+ 1) * sizeof(*debug_channels
));
644 debug_channels
[nb_debug_channels
++] = xstrdup(name
);
648 /*******************************************************************
649 * parse_debug_channels
651 * Parse a source file and extract the debug channel definitions.
653 int parse_debug_channels( const char *srcdir
, const char *filename
)
658 file
= open_input_file( srcdir
, filename
);
659 while (fgets( ParseBuffer
, sizeof(ParseBuffer
), file
))
661 char *channel
, *end
, *p
= ParseBuffer
;
663 p
= ParseBuffer
+ strlen(ParseBuffer
) - 1;
664 if (!eol_seen
) /* continuation line */
666 eol_seen
= (*p
== '\n');
669 if ((eol_seen
= (*p
== '\n'))) *p
= 0;
672 while (isspace(*p
)) p
++;
673 if (!memcmp( p
, "WINE_DECLARE_DEBUG_CHANNEL", 26 ) ||
674 !memcmp( p
, "WINE_DEFAULT_DEBUG_CHANNEL", 26 ))
677 while (isspace(*p
)) p
++;
680 error( "invalid debug channel specification '%s'\n", ParseBuffer
);
684 while (isspace(*p
)) p
++;
687 error( "invalid debug channel specification '%s'\n", ParseBuffer
);
691 while (isalnum(*p
) || *p
== '_') p
++;
693 while (isspace(*p
)) p
++;
696 error( "invalid debug channel specification '%s'\n", ParseBuffer
);
700 add_debug_channel( channel
);
705 close_input_file( file
);