Name all sections of type sect1.
[wine.git] / tools / winebuild / parser.c
blob0b6118b4668f8df1cd8971318bf12f8dd5b49b8c
1 /*
2 * Spec file parser
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
25 #include "config.h"
26 #include "wine/port.h"
28 #include <assert.h>
29 #include <ctype.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
34 #include "winbase.h"
35 #include "build.h"
37 int current_line = 0;
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 NULL
68 static int IsNumberString(const char *s)
70 while (*s) if (!isdigit(*s++)) return 0;
71 return 1;
74 inline static int is_token_separator( char ch )
76 return (ch == '(' || ch == ')' || ch == '-');
79 /* get the next line from the input file, or return 0 if at eof */
80 static int get_next_line(void)
82 ParseNext = ParseBuffer;
83 current_line++;
84 return (fgets(ParseBuffer, sizeof(ParseBuffer), input_file) != NULL);
87 static const char * GetToken( int allow_eol )
89 char *p = ParseNext;
90 char *token = TokenBuffer;
92 for (;;)
94 /* remove initial white space */
95 p = ParseNext;
96 while (isspace(*p)) p++;
98 if (*p == '\\' && p[1] == '\n') /* line continuation */
100 if (!get_next_line())
102 if (!allow_eol) error( "Unexpected end of file\n" );
103 return NULL;
106 else break;
109 if ((*p == '\0') || (*p == '#'))
111 if (!allow_eol) error( "Declaration not terminated properly\n" );
112 return NULL;
116 * Find end of token.
118 if (is_token_separator(*p))
120 /* a separator is always a complete token */
121 *token++ = *p++;
123 else while (*p != '\0' && !is_token_separator(*p) && !isspace(*p))
125 if (*p == '\\') p++;
126 if (*p) *token++ = *p++;
128 *token = '\0';
129 ParseNext = p;
130 return TokenBuffer;
134 /*******************************************************************
135 * ParseVariable
137 * Parse a variable definition.
139 static int ParseVariable( ORDDEF *odp )
141 char *endptr;
142 int *value_array;
143 int n_values;
144 int value_array_size;
145 const char *token;
147 if (SpecType == SPEC_WIN32)
149 error( "'variable' not supported in Win32, use 'extern' instead\n" );
150 return 0;
153 if (!(token = GetToken(0))) return 0;
154 if (*token != '(')
156 error( "Expected '(' got '%s'\n", token );
157 return 0;
160 n_values = 0;
161 value_array_size = 25;
162 value_array = xmalloc(sizeof(*value_array) * value_array_size);
164 for (;;)
166 if (!(token = GetToken(0)))
168 free( value_array );
169 return 0;
171 if (*token == ')')
172 break;
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')
184 error( "Expected number value, got '%s'\n", token );
185 free( value_array );
186 return 0;
190 odp->u.var.n_values = n_values;
191 odp->u.var.values = xrealloc(value_array, sizeof(*value_array) * n_values);
192 return 1;
196 /*******************************************************************
197 * ParseExportFunction
199 * Parse a function definition.
201 static int ParseExportFunction( ORDDEF *odp )
203 const char *token;
204 unsigned int i;
206 switch(SpecType)
208 case SPEC_WIN16:
209 if (odp->type == TYPE_STDCALL)
211 error( "'stdcall' not supported for Win16\n" );
212 return 0;
214 if (odp->type == TYPE_VARARGS)
216 error( "'varargs' not supported for Win16\n" );
217 return 0;
219 break;
220 case SPEC_WIN32:
221 if ((odp->type == TYPE_PASCAL) || (odp->type == TYPE_PASCAL_16))
223 error( "'pascal' not supported for Win32\n" );
224 return 0;
226 if (odp->flags & FLAG_INTERRUPT)
228 error( "'interrupt' not supported for Win32\n" );
229 return 0;
231 break;
232 default:
233 break;
236 if (!(token = GetToken(0))) return 0;
237 if (*token != '(')
239 error( "Expected '(' got '%s'\n", token );
240 return 0;
243 for (i = 0; i < sizeof(odp->u.func.arg_types); i++)
245 if (!(token = GetToken(0))) return 0;
246 if (*token == ')')
247 break;
249 if (!strcmp(token, "word"))
250 odp->u.func.arg_types[i] = 'w';
251 else if (!strcmp(token, "s_word"))
252 odp->u.func.arg_types[i] = 's';
253 else if (!strcmp(token, "long") || !strcmp(token, "segptr"))
254 odp->u.func.arg_types[i] = 'l';
255 else if (!strcmp(token, "ptr"))
256 odp->u.func.arg_types[i] = 'p';
257 else if (!strcmp(token, "str"))
258 odp->u.func.arg_types[i] = 't';
259 else if (!strcmp(token, "wstr"))
260 odp->u.func.arg_types[i] = 'W';
261 else if (!strcmp(token, "segstr"))
262 odp->u.func.arg_types[i] = 'T';
263 else if (!strcmp(token, "double"))
265 odp->u.func.arg_types[i++] = 'l';
266 if (i < sizeof(odp->u.func.arg_types)) odp->u.func.arg_types[i] = 'l';
268 else
270 error( "Unknown argument type '%s'\n", token );
271 return 0;
274 if (SpecType == SPEC_WIN32)
276 if (strcmp(token, "long") &&
277 strcmp(token, "ptr") &&
278 strcmp(token, "str") &&
279 strcmp(token, "wstr") &&
280 strcmp(token, "double"))
282 error( "Type '%s' not supported for Win32\n", token );
283 return 0;
287 if ((*token != ')') || (i >= sizeof(odp->u.func.arg_types)))
289 error( "Too many arguments\n" );
290 return 0;
293 odp->u.func.arg_types[i] = '\0';
294 if (odp->type == TYPE_VARARGS)
295 odp->flags |= FLAG_NORELAY; /* no relay debug possible for varags entry point */
297 if (!(token = GetToken(1)))
299 if (!strcmp( odp->name, "@" ))
301 error( "Missing handler name for anonymous function\n" );
302 return 0;
304 odp->link_name = xstrdup( odp->name );
306 else
308 odp->link_name = xstrdup( token );
309 if (strchr( odp->link_name, '.' ))
311 if (SpecType == SPEC_WIN16)
313 error( "Forwarded functions not supported for Win16\n" );
314 return 0;
316 odp->flags |= FLAG_FORWARD;
319 return 1;
323 /*******************************************************************
324 * ParseEquate
326 * Parse an 'equate' definition.
328 static int ParseEquate( ORDDEF *odp )
330 char *endptr;
331 int value;
332 const char *token;
334 if (SpecType == SPEC_WIN32)
336 error( "'equate' not supported for Win32\n" );
337 return 0;
339 if (!(token = GetToken(0))) return 0;
340 value = strtol(token, &endptr, 0);
341 if (endptr == NULL || *endptr != '\0')
343 error( "Expected number value, got '%s'\n", token );
344 return 0;
346 odp->u.abs.value = value;
347 return 1;
351 /*******************************************************************
352 * ParseStub
354 * Parse a 'stub' definition.
356 static int ParseStub( ORDDEF *odp )
358 odp->u.func.arg_types[0] = '\0';
359 odp->link_name = xstrdup("");
360 return 1;
364 /*******************************************************************
365 * ParseExtern
367 * Parse an 'extern' definition.
369 static int ParseExtern( ORDDEF *odp )
371 const char *token;
373 if (SpecType == SPEC_WIN16)
375 error( "'extern' not supported for Win16, use 'variable' instead\n" );
376 return 0;
378 if (!(token = GetToken(1)))
380 if (!strcmp( odp->name, "@" ))
382 error( "Missing handler name for anonymous extern\n" );
383 return 0;
385 odp->link_name = xstrdup( odp->name );
387 else
389 odp->link_name = xstrdup( token );
390 if (strchr( odp->link_name, '.' )) odp->flags |= FLAG_FORWARD;
392 return 1;
396 /*******************************************************************
397 * ParseFlags
399 * Parse the optional flags for an entry point
401 static const char *ParseFlags( ORDDEF *odp )
403 unsigned int i;
404 const char *token;
408 if (!(token = GetToken(0))) break;
409 for (i = 0; FlagNames[i]; i++)
410 if (!strcmp( FlagNames[i], token )) break;
411 if (!FlagNames[i])
413 error( "Unknown flag '%s'\n", token );
414 return NULL;
416 odp->flags |= 1 << i;
417 token = GetToken(0);
418 } while (token && *token == '-');
420 return token;
423 /*******************************************************************
424 * fix_export_name
426 * Fix an exported function name by removing a possible @xx suffix
428 static void fix_export_name( char *name )
430 char *p, *end = strrchr( name, '@' );
431 if (!end || !end[1] || end == name) return;
432 /* make sure all the rest is digits */
433 for (p = end + 1; *p; p++) if (!isdigit(*p)) return;
434 *end = 0;
437 /*******************************************************************
438 * ParseOrdinal
440 * Parse an ordinal definition.
442 static int ParseOrdinal(int ordinal)
444 const char *token;
446 ORDDEF *odp = xmalloc( sizeof(*odp) );
447 memset( odp, 0, sizeof(*odp) );
448 EntryPoints[nb_entry_points++] = odp;
450 if (!(token = GetToken(0))) goto error;
452 for (odp->type = 0; odp->type < TYPE_NBTYPES; odp->type++)
453 if (TypeNames[odp->type] && !strcmp( token, TypeNames[odp->type] ))
454 break;
456 if (odp->type >= TYPE_NBTYPES)
458 error( "Expected type after ordinal, found '%s' instead\n", token );
459 goto error;
462 if (!(token = GetToken(0))) goto error;
463 if (*token == '-' && !(token = ParseFlags( odp ))) goto error;
465 odp->name = xstrdup( token );
466 fix_export_name( odp->name );
467 odp->lineno = current_line;
468 odp->ordinal = ordinal;
470 switch(odp->type)
472 case TYPE_VARIABLE:
473 if (!ParseVariable( odp )) goto error;
474 break;
475 case TYPE_PASCAL_16:
476 case TYPE_PASCAL:
477 case TYPE_STDCALL:
478 case TYPE_VARARGS:
479 case TYPE_CDECL:
480 if (!ParseExportFunction( odp )) goto error;
481 break;
482 case TYPE_ABS:
483 if (!ParseEquate( odp )) goto error;
484 break;
485 case TYPE_STUB:
486 if (!ParseStub( odp )) goto error;
487 break;
488 case TYPE_EXTERN:
489 if (!ParseExtern( odp )) goto error;
490 break;
491 default:
492 assert( 0 );
495 #ifndef __i386__
496 if (odp->flags & FLAG_I386)
498 /* ignore this entry point on non-Intel archs */
499 EntryPoints[--nb_entry_points] = NULL;
500 free( odp );
501 return 1;
503 #endif
505 if (ordinal != -1)
507 if (!ordinal)
509 error( "Ordinal 0 is not valid\n" );
510 goto error;
512 if (ordinal >= MAX_ORDINALS)
514 error( "Ordinal number %d too large\n", ordinal );
515 goto error;
517 if (ordinal > Limit) Limit = ordinal;
518 if (ordinal < Base) Base = ordinal;
519 odp->ordinal = ordinal;
520 if (Ordinals[ordinal])
522 error( "Duplicate ordinal %d\n", ordinal );
523 goto error;
525 Ordinals[ordinal] = odp;
528 if (!strcmp( odp->name, "@" ) || odp->flags & FLAG_NONAME)
530 if (ordinal == -1)
532 error( "Nameless function needs an explicit ordinal number\n" );
533 goto error;
535 if (SpecType != SPEC_WIN32)
537 error( "Nameless functions not supported for Win16\n" );
538 goto error;
540 if (!strcmp( odp->name, "@" )) free( odp->name );
541 else odp->export_name = odp->name;
542 odp->name = NULL;
544 else Names[nb_names++] = odp;
545 return 1;
547 error:
548 EntryPoints[--nb_entry_points] = NULL;
549 free( odp->name );
550 free( odp );
551 return 0;
555 static int name_compare( const void *name1, const void *name2 )
557 ORDDEF *odp1 = *(ORDDEF **)name1;
558 ORDDEF *odp2 = *(ORDDEF **)name2;
559 return strcmp( odp1->name, odp2->name );
562 /*******************************************************************
563 * sort_names
565 * Sort the name array and catch duplicates.
567 static void sort_names(void)
569 int i;
571 if (!nb_names) return;
573 /* sort the list of names */
574 qsort( Names, nb_names, sizeof(Names[0]), name_compare );
576 /* check for duplicate names */
577 for (i = 0; i < nb_names - 1; i++)
579 if (!strcmp( Names[i]->name, Names[i+1]->name ))
581 current_line = max( Names[i]->lineno, Names[i+1]->lineno );
582 error( "'%s' redefined\n%s:%d: First defined here\n",
583 Names[i]->name, input_file_name,
584 min( Names[i]->lineno, Names[i+1]->lineno ) );
590 /*******************************************************************
591 * ParseTopLevel
593 * Parse a spec file.
595 int ParseTopLevel( FILE *file )
597 const char *token;
599 input_file = file;
600 current_line = 0;
602 while (get_next_line())
604 if (!(token = GetToken(1))) continue;
605 if (strcmp(token, "@") == 0)
607 if (SpecType != SPEC_WIN32)
609 error( "'@' ordinals not supported for Win16\n" );
610 continue;
612 if (!ParseOrdinal( -1 )) continue;
614 else if (IsNumberString(token))
616 if (!ParseOrdinal( atoi(token) )) continue;
618 else
620 error( "Expected ordinal declaration, got '%s'\n", token );
621 continue;
623 if ((token = GetToken(1))) error( "Syntax error near '%s'\n", token );
626 current_line = 0; /* no longer parsing the input file */
627 sort_names();
628 return !nb_errors;
632 /*******************************************************************
633 * add_debug_channel
635 static void add_debug_channel( const char *name )
637 int i;
639 for (i = 0; i < nb_debug_channels; i++)
640 if (!strcmp( debug_channels[i], name )) return;
642 debug_channels = xrealloc( debug_channels, (nb_debug_channels + 1) * sizeof(*debug_channels));
643 debug_channels[nb_debug_channels++] = xstrdup(name);
647 /*******************************************************************
648 * parse_debug_channels
650 * Parse a source file and extract the debug channel definitions.
652 int parse_debug_channels( const char *srcdir, const char *filename )
654 FILE *file;
655 int eol_seen = 1;
657 file = open_input_file( srcdir, filename );
658 while (fgets( ParseBuffer, sizeof(ParseBuffer), file ))
660 char *channel, *end, *p = ParseBuffer;
662 p = ParseBuffer + strlen(ParseBuffer) - 1;
663 if (!eol_seen) /* continuation line */
665 eol_seen = (*p == '\n');
666 continue;
668 if ((eol_seen = (*p == '\n'))) *p = 0;
670 p = ParseBuffer;
671 while (isspace(*p)) p++;
672 if (!memcmp( p, "WINE_DECLARE_DEBUG_CHANNEL", 26 ) ||
673 !memcmp( p, "WINE_DEFAULT_DEBUG_CHANNEL", 26 ))
675 p += 26;
676 while (isspace(*p)) p++;
677 if (*p != '(')
679 error( "invalid debug channel specification '%s'\n", ParseBuffer );
680 goto next;
682 p++;
683 while (isspace(*p)) p++;
684 if (!isalpha(*p))
686 error( "invalid debug channel specification '%s'\n", ParseBuffer );
687 goto next;
689 channel = p;
690 while (isalnum(*p) || *p == '_') p++;
691 end = p;
692 while (isspace(*p)) p++;
693 if (*p != ')')
695 error( "invalid debug channel specification '%s'\n", ParseBuffer );
696 goto next;
698 *end = 0;
699 add_debug_channel( channel );
701 next:
702 current_line++;
704 close_input_file( file );
705 return !nb_errors;