Fix subclassing to support nested messages.
[wine] / tools / winebuild / parser.c
1 /*
2  * Spec file parser
3  *
4  * Copyright 1993 Robert J. Amstadt
5  * Copyright 1995 Martin von Loewis
6  * Copyright 1995, 1996, 1997, 2004 Alexandre Julliard
7  * Copyright 1997 Eric Youngdale
8  * Copyright 1999 Ulrich Weigand
9  *
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.
14  *
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.
19  *
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
23  */
24
25 #include "config.h"
26 #include "wine/port.h"
27
28 #include <assert.h>
29 #include <ctype.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include "windef.h"
36 #include "winbase.h"
37 #include "build.h"
38
39 int current_line = 0;
40
41 static char ParseBuffer[512];
42 static char TokenBuffer[512];
43 static char *ParseNext = ParseBuffer;
44 static FILE *input_file;
45
46 static const char *separator_chars;
47 static const char *comment_chars;
48
49 static const char * const TypeNames[TYPE_NBTYPES] =
50 {
51     "variable",     /* TYPE_VARIABLE */
52     "pascal",       /* TYPE_PASCAL */
53     "equate",       /* TYPE_ABS */
54     "stub",         /* TYPE_STUB */
55     "stdcall",      /* TYPE_STDCALL */
56     "cdecl",        /* TYPE_CDECL */
57     "varargs",      /* TYPE_VARARGS */
58     "extern"        /* TYPE_EXTERN */
59 };
60
61 static const char * const FlagNames[] =
62 {
63     "norelay",     /* FLAG_NORELAY */
64     "noname",      /* FLAG_NONAME */
65     "ret16",       /* FLAG_RET16 */
66     "ret64",       /* FLAG_RET64 */
67     "i386",        /* FLAG_I386 */
68     "register",    /* FLAG_REGISTER */
69     "interrupt",   /* FLAG_INTERRUPT */
70     "private",     /* FLAG_PRIVATE */
71     NULL
72 };
73
74 static int IsNumberString(const char *s)
75 {
76     while (*s) if (!isdigit(*s++)) return 0;
77     return 1;
78 }
79
80 inline static int is_token_separator( char ch )
81 {
82     return strchr( separator_chars, ch ) != NULL;
83 }
84
85 inline static int is_token_comment( char ch )
86 {
87     return strchr( comment_chars, ch ) != NULL;
88 }
89
90 /* get the next line from the input file, or return 0 if at eof */
91 static int get_next_line(void)
92 {
93     ParseNext = ParseBuffer;
94     current_line++;
95     return (fgets(ParseBuffer, sizeof(ParseBuffer), input_file) != NULL);
96 }
97
98 static const char * GetToken( int allow_eol )
99 {
100     char *p = ParseNext;
101     char *token = TokenBuffer;
102
103     for (;;)
104     {
105         /* remove initial white space */
106         p = ParseNext;
107         while (isspace(*p)) p++;
108
109         if (*p == '\\' && p[1] == '\n')  /* line continuation */
110         {
111             if (!get_next_line())
112             {
113                 if (!allow_eol) error( "Unexpected end of file\n" );
114                 return NULL;
115             }
116         }
117         else break;
118     }
119
120     if ((*p == '\0') || is_token_comment(*p))
121     {
122         if (!allow_eol) error( "Declaration not terminated properly\n" );
123         return NULL;
124     }
125
126     /*
127      * Find end of token.
128      */
129     if (is_token_separator(*p))
130     {
131         /* a separator is always a complete token */
132         *token++ = *p++;
133     }
134     else while (*p != '\0' && !is_token_separator(*p) && !isspace(*p))
135     {
136         if (*p == '\\') p++;
137         if (*p) *token++ = *p++;
138     }
139     *token = '\0';
140     ParseNext = p;
141     return TokenBuffer;
142 }
143
144
145 static ORDDEF *add_entry_point( DLLSPEC *spec )
146 {
147     if (spec->nb_entry_points == spec->alloc_entry_points)
148     {
149         spec->alloc_entry_points += 128;
150         spec->entry_points = xrealloc( spec->entry_points,
151                                        spec->alloc_entry_points * sizeof(*spec->entry_points) );
152     }
153     return &spec->entry_points[spec->nb_entry_points++];
154 }
155
156 /*******************************************************************
157  *         parse_spec_variable
158  *
159  * Parse a variable definition in a .spec file.
160  */
161 static int parse_spec_variable( ORDDEF *odp, DLLSPEC *spec )
162 {
163     char *endptr;
164     int *value_array;
165     int n_values;
166     int value_array_size;
167     const char *token;
168
169     if (spec->type == SPEC_WIN32)
170     {
171         error( "'variable' not supported in Win32, use 'extern' instead\n" );
172         return 0;
173     }
174
175     if (!(token = GetToken(0))) return 0;
176     if (*token != '(')
177     {
178         error( "Expected '(' got '%s'\n", token );
179         return 0;
180     }
181
182     n_values = 0;
183     value_array_size = 25;
184     value_array = xmalloc(sizeof(*value_array) * value_array_size);
185
186     for (;;)
187     {
188         if (!(token = GetToken(0)))
189         {
190             free( value_array );
191             return 0;
192         }
193         if (*token == ')')
194             break;
195
196         value_array[n_values++] = strtol(token, &endptr, 0);
197         if (n_values == value_array_size)
198         {
199             value_array_size += 25;
200             value_array = xrealloc(value_array,
201                                    sizeof(*value_array) * value_array_size);
202         }
203
204         if (endptr == NULL || *endptr != '\0')
205         {
206             error( "Expected number value, got '%s'\n", token );
207             free( value_array );
208             return 0;
209         }
210     }
211
212     odp->u.var.n_values = n_values;
213     odp->u.var.values = xrealloc(value_array, sizeof(*value_array) * n_values);
214     return 1;
215 }
216
217
218 /*******************************************************************
219  *         parse_spec_export
220  *
221  * Parse an exported function definition in a .spec file.
222  */
223 static int parse_spec_export( ORDDEF *odp, DLLSPEC *spec )
224 {
225     const char *token;
226     unsigned int i;
227
228     switch(spec->type)
229     {
230     case SPEC_WIN16:
231         if (odp->type == TYPE_STDCALL)
232         {
233             error( "'stdcall' not supported for Win16\n" );
234             return 0;
235         }
236         break;
237     case SPEC_WIN32:
238         if (odp->type == TYPE_PASCAL)
239         {
240             error( "'pascal' not supported for Win32\n" );
241             return 0;
242         }
243         if (odp->flags & FLAG_INTERRUPT)
244         {
245             error( "'interrupt' not supported for Win32\n" );
246             return 0;
247         }
248         break;
249     default:
250         break;
251     }
252
253     if (!(token = GetToken(0))) return 0;
254     if (*token != '(')
255     {
256         error( "Expected '(' got '%s'\n", token );
257         return 0;
258     }
259
260     for (i = 0; i < sizeof(odp->u.func.arg_types); i++)
261     {
262         if (!(token = GetToken(0))) return 0;
263         if (*token == ')')
264             break;
265
266         if (!strcmp(token, "word"))
267             odp->u.func.arg_types[i] = 'w';
268         else if (!strcmp(token, "s_word"))
269             odp->u.func.arg_types[i] = 's';
270         else if (!strcmp(token, "long") || !strcmp(token, "segptr"))
271             odp->u.func.arg_types[i] = 'l';
272         else if (!strcmp(token, "ptr"))
273             odp->u.func.arg_types[i] = 'p';
274         else if (!strcmp(token, "str"))
275             odp->u.func.arg_types[i] = 't';
276         else if (!strcmp(token, "wstr"))
277             odp->u.func.arg_types[i] = 'W';
278         else if (!strcmp(token, "segstr"))
279             odp->u.func.arg_types[i] = 'T';
280         else if (!strcmp(token, "double"))
281         {
282             odp->u.func.arg_types[i++] = 'l';
283             if (i < sizeof(odp->u.func.arg_types)) odp->u.func.arg_types[i] = 'l';
284         }
285         else
286         {
287             error( "Unknown argument type '%s'\n", token );
288             return 0;
289         }
290
291         if (spec->type == SPEC_WIN32)
292         {
293             if (strcmp(token, "long") &&
294                 strcmp(token, "ptr") &&
295                 strcmp(token, "str") &&
296                 strcmp(token, "wstr") &&
297                 strcmp(token, "double"))
298             {
299                 error( "Type '%s' not supported for Win32\n", token );
300                 return 0;
301             }
302         }
303     }
304     if ((*token != ')') || (i >= sizeof(odp->u.func.arg_types)))
305     {
306         error( "Too many arguments\n" );
307         return 0;
308     }
309
310     odp->u.func.arg_types[i] = '\0';
311     if (odp->type == TYPE_VARARGS)
312         odp->flags |= FLAG_NORELAY;  /* no relay debug possible for varags entry point */
313
314     if (!(token = GetToken(1)))
315     {
316         if (!strcmp( odp->name, "@" ))
317         {
318             error( "Missing handler name for anonymous function\n" );
319             return 0;
320         }
321         odp->link_name = xstrdup( odp->name );
322     }
323     else
324     {
325         odp->link_name = xstrdup( token );
326         if (strchr( odp->link_name, '.' ))
327         {
328             if (spec->type == SPEC_WIN16)
329             {
330                 error( "Forwarded functions not supported for Win16\n" );
331                 return 0;
332             }
333             odp->flags |= FLAG_FORWARD;
334         }
335     }
336     return 1;
337 }
338
339
340 /*******************************************************************
341  *         parse_spec_equate
342  *
343  * Parse an 'equate' definition in a .spec file.
344  */
345 static int parse_spec_equate( ORDDEF *odp, DLLSPEC *spec )
346 {
347     char *endptr;
348     int value;
349     const char *token;
350
351     if (spec->type == SPEC_WIN32)
352     {
353         error( "'equate' not supported for Win32\n" );
354         return 0;
355     }
356     if (!(token = GetToken(0))) return 0;
357     value = strtol(token, &endptr, 0);
358     if (endptr == NULL || *endptr != '\0')
359     {
360         error( "Expected number value, got '%s'\n", token );
361         return 0;
362     }
363     odp->u.abs.value = value;
364     return 1;
365 }
366
367
368 /*******************************************************************
369  *         parse_spec_stub
370  *
371  * Parse a 'stub' definition in a .spec file
372  */
373 static int parse_spec_stub( ORDDEF *odp, DLLSPEC *spec )
374 {
375     odp->u.func.arg_types[0] = '\0';
376     odp->link_name = xstrdup("");
377     return 1;
378 }
379
380
381 /*******************************************************************
382  *         parse_spec_extern
383  *
384  * Parse an 'extern' definition in a .spec file.
385  */
386 static int parse_spec_extern( ORDDEF *odp, DLLSPEC *spec )
387 {
388     const char *token;
389
390     if (spec->type == SPEC_WIN16)
391     {
392         error( "'extern' not supported for Win16, use 'variable' instead\n" );
393         return 0;
394     }
395     if (!(token = GetToken(1)))
396     {
397         if (!strcmp( odp->name, "@" ))
398         {
399             error( "Missing handler name for anonymous extern\n" );
400             return 0;
401         }
402         odp->link_name = xstrdup( odp->name );
403     }
404     else
405     {
406         odp->link_name = xstrdup( token );
407         if (strchr( odp->link_name, '.' )) odp->flags |= FLAG_FORWARD;
408     }
409     return 1;
410 }
411
412
413 /*******************************************************************
414  *         parse_spec_flags
415  *
416  * Parse the optional flags for an entry point in a .spec file.
417  */
418 static const char *parse_spec_flags( ORDDEF *odp )
419 {
420     unsigned int i;
421     const char *token;
422
423     do
424     {
425         if (!(token = GetToken(0))) break;
426         for (i = 0; FlagNames[i]; i++)
427             if (!strcmp( FlagNames[i], token )) break;
428         if (!FlagNames[i])
429         {
430             error( "Unknown flag '%s'\n", token );
431             return NULL;
432         }
433         odp->flags |= 1 << i;
434         token = GetToken(0);
435     } while (token && *token == '-');
436
437     return token;
438 }
439
440
441 /*******************************************************************
442  *         parse_spec_ordinal
443  *
444  * Parse an ordinal definition in a .spec file.
445  */
446 static int parse_spec_ordinal( int ordinal, DLLSPEC *spec )
447 {
448     const char *token;
449
450     ORDDEF *odp = add_entry_point( spec );
451     memset( odp, 0, sizeof(*odp) );
452
453     if (!(token = GetToken(0))) goto error;
454
455     for (odp->type = 0; odp->type < TYPE_NBTYPES; odp->type++)
456         if (TypeNames[odp->type] && !strcmp( token, TypeNames[odp->type] ))
457             break;
458
459     if (odp->type >= TYPE_NBTYPES)
460     {
461         error( "Expected type after ordinal, found '%s' instead\n", token );
462         goto error;
463     }
464
465     if (!(token = GetToken(0))) goto error;
466     if (*token == '-' && !(token = parse_spec_flags( odp ))) goto error;
467
468     odp->name = xstrdup( token );
469     remove_stdcall_decoration( odp->name );
470     odp->lineno = current_line;
471     odp->ordinal = ordinal;
472
473     switch(odp->type)
474     {
475     case TYPE_VARIABLE:
476         if (!parse_spec_variable( odp, spec )) goto error;
477         break;
478     case TYPE_PASCAL:
479     case TYPE_STDCALL:
480     case TYPE_VARARGS:
481     case TYPE_CDECL:
482         if (!parse_spec_export( odp, spec )) goto error;
483         break;
484     case TYPE_ABS:
485         if (!parse_spec_equate( odp, spec )) goto error;
486         break;
487     case TYPE_STUB:
488         if (!parse_spec_stub( odp, spec )) goto error;
489         break;
490     case TYPE_EXTERN:
491         if (!parse_spec_extern( odp, spec )) goto error;
492         break;
493     default:
494         assert( 0 );
495     }
496
497 #ifndef __i386__
498     if (odp->flags & FLAG_I386)
499     {
500         /* ignore this entry point on non-Intel archs */
501         spec->nb_entry_points--;
502         return 1;
503     }
504 #endif
505
506     if (ordinal != -1)
507     {
508         if (!ordinal)
509         {
510             error( "Ordinal 0 is not valid\n" );
511             goto error;
512         }
513         if (ordinal >= MAX_ORDINALS)
514         {
515             error( "Ordinal number %d too large\n", ordinal );
516             goto error;
517         }
518         if (ordinal > spec->limit) spec->limit = ordinal;
519         if (ordinal < spec->base) spec->base = ordinal;
520         odp->ordinal = ordinal;
521     }
522
523     if (!strcmp( odp->name, "@" ) || odp->flags & FLAG_NONAME)
524     {
525         if (ordinal == -1)
526         {
527             error( "Nameless function needs an explicit ordinal number\n" );
528             goto error;
529         }
530         if (spec->type != SPEC_WIN32)
531         {
532             error( "Nameless functions not supported for Win16\n" );
533             goto error;
534         }
535         if (!strcmp( odp->name, "@" )) free( odp->name );
536         else odp->export_name = odp->name;
537         odp->name = NULL;
538     }
539     return 1;
540
541 error:
542     spec->nb_entry_points--;
543     free( odp->name );
544     return 0;
545 }
546
547
548 static int name_compare( const void *name1, const void *name2 )
549 {
550     ORDDEF *odp1 = *(ORDDEF **)name1;
551     ORDDEF *odp2 = *(ORDDEF **)name2;
552     return strcmp( odp1->name, odp2->name );
553 }
554
555 /*******************************************************************
556  *         assign_names
557  *
558  * Build the name array and catch duplicates.
559  */
560 static void assign_names( DLLSPEC *spec )
561 {
562     int i, j;
563
564     spec->nb_names = 0;
565     for (i = 0; i < spec->nb_entry_points; i++)
566         if (spec->entry_points[i].name) spec->nb_names++;
567     if (!spec->nb_names) return;
568
569     spec->names = xmalloc( spec->nb_names * sizeof(spec->names[0]) );
570     for (i = j = 0; i < spec->nb_entry_points; i++)
571         if (spec->entry_points[i].name) spec->names[j++] = &spec->entry_points[i];
572
573     /* sort the list of names */
574     qsort( spec->names, spec->nb_names, sizeof(spec->names[0]), name_compare );
575
576     /* check for duplicate names */
577     for (i = 0; i < spec->nb_names - 1; i++)
578     {
579         if (!strcmp( spec->names[i]->name, spec->names[i+1]->name ))
580         {
581             current_line = max( spec->names[i]->lineno, spec->names[i+1]->lineno );
582             error( "'%s' redefined\n%s:%d: First defined here\n",
583                    spec->names[i]->name, input_file_name,
584                    min( spec->names[i]->lineno, spec->names[i+1]->lineno ) );
585         }
586     }
587 }
588
589 /*******************************************************************
590  *         assign_ordinals
591  *
592  * Build the ordinal array.
593  */
594 static void assign_ordinals( DLLSPEC *spec )
595 {
596     int i, count, ordinal;
597
598     /* start assigning from base, or from 1 if no ordinal defined yet */
599     if (spec->base == MAX_ORDINALS) spec->base = 1;
600     if (spec->limit < spec->base) spec->limit = spec->base;
601
602     count = max( spec->limit + 1, spec->base + spec->nb_entry_points );
603     spec->ordinals = xmalloc( count * sizeof(spec->ordinals[0]) );
604     memset( spec->ordinals, 0, count * sizeof(spec->ordinals[0]) );
605
606     /* fill in all explicitly specified ordinals */
607     for (i = 0; i < spec->nb_entry_points; i++)
608     {
609         ordinal = spec->entry_points[i].ordinal;
610         if (ordinal == -1) continue;
611         if (spec->ordinals[ordinal])
612         {
613             current_line = max( spec->entry_points[i].lineno, spec->ordinals[ordinal]->lineno );
614             error( "ordinal %d redefined\n%s:%d: First defined here\n",
615                    ordinal, input_file_name,
616                    min( spec->entry_points[i].lineno, spec->ordinals[ordinal]->lineno ) );
617         }
618         else spec->ordinals[ordinal] = &spec->entry_points[i];
619     }
620
621     /* now assign ordinals to the rest */
622     for (i = 0, ordinal = spec->base; i < spec->nb_names; i++)
623     {
624         if (spec->names[i]->ordinal != -1) continue;  /* already has an ordinal */
625         while (spec->ordinals[ordinal]) ordinal++;
626         if (ordinal >= MAX_ORDINALS)
627         {
628             current_line = spec->names[i]->lineno;
629             fatal_error( "Too many functions defined (max %d)\n", MAX_ORDINALS );
630         }
631         spec->names[i]->ordinal = ordinal;
632         spec->ordinals[ordinal] = spec->names[i];
633     }
634     if (ordinal > spec->limit) spec->limit = ordinal;
635 }
636
637
638 /*******************************************************************
639  *         parse_spec_file
640  *
641  * Parse a .spec file.
642  */
643 int parse_spec_file( FILE *file, DLLSPEC *spec )
644 {
645     const char *token;
646
647     input_file = file;
648     current_line = 0;
649
650     comment_chars = "#;";
651     separator_chars = "()-";
652
653     while (get_next_line())
654     {
655         if (!(token = GetToken(1))) continue;
656         if (strcmp(token, "@") == 0)
657         {
658             if (spec->type != SPEC_WIN32)
659             {
660                 error( "'@' ordinals not supported for Win16\n" );
661                 continue;
662             }
663             if (!parse_spec_ordinal( -1, spec )) continue;
664         }
665         else if (IsNumberString(token))
666         {
667             if (!parse_spec_ordinal( atoi(token), spec )) continue;
668         }
669         else
670         {
671             error( "Expected ordinal declaration, got '%s'\n", token );
672             continue;
673         }
674         if ((token = GetToken(1))) error( "Syntax error near '%s'\n", token );
675     }
676
677     current_line = 0;  /* no longer parsing the input file */
678     assign_names( spec );
679     assign_ordinals( spec );
680     return !nb_errors;
681 }
682
683
684 /*******************************************************************
685  *         parse_def_library
686  *
687  * Parse a LIBRARY declaration in a .def file.
688  */
689 static int parse_def_library( DLLSPEC *spec )
690 {
691     const char *token = GetToken(1);
692
693     if (!token) return 1;
694     if (strcmp( token, "BASE" ))
695     {
696         free( spec->file_name );
697         spec->file_name = xstrdup( token );
698         if (!(token = GetToken(1))) return 1;
699     }
700     if (strcmp( token, "BASE" ))
701     {
702         error( "Expected library name or BASE= declaration, got '%s'\n", token );
703         return 0;
704     }
705     if (!(token = GetToken(0))) return 0;
706     if (strcmp( token, "=" ))
707     {
708         error( "Expected '=' after BASE, got '%s'\n", token );
709         return 0;
710     }
711     if (!(token = GetToken(0))) return 0;
712     /* FIXME: do something with base address */
713
714     return 1;
715 }
716
717
718 /*******************************************************************
719  *         parse_def_stack_heap_size
720  *
721  * Parse a STACKSIZE or HEAPSIZE declaration in a .def file.
722  */
723 static int parse_def_stack_heap_size( int is_stack, DLLSPEC *spec )
724 {
725     const char *token = GetToken(0);
726     char *end;
727     unsigned long size;
728
729     if (!token) return 0;
730     size = strtoul( token, &end, 0 );
731     if (*end)
732     {
733         error( "Invalid number '%s'\n", token );
734         return 0;
735     }
736     if (is_stack) spec->stack_size = size / 1024;
737     else spec->heap_size = size / 1024;
738     if (!(token = GetToken(1))) return 1;
739     if (strcmp( token, "," ))
740     {
741         error( "Expected ',' after size, got '%s'\n", token );
742         return 0;
743     }
744     if (!(token = GetToken(0))) return 0;
745     /* FIXME: do something with reserve size */
746     return 1;
747 }
748
749
750 /*******************************************************************
751  *         parse_def_export
752  *
753  * Parse an export declaration in a .def file.
754  */
755 static int parse_def_export( char *name, DLLSPEC *spec )
756 {
757     int i, args;
758     const char *token = GetToken(1);
759
760     ORDDEF *odp = add_entry_point( spec );
761     memset( odp, 0, sizeof(*odp) );
762
763     odp->lineno = current_line;
764     odp->ordinal = -1;
765     odp->name = name;
766     args = remove_stdcall_decoration( odp->name );
767     if (args == -1) odp->type = TYPE_CDECL;
768     else
769     {
770         odp->type = TYPE_STDCALL;
771         args /= sizeof(int);
772         if (args >= sizeof(odp->u.func.arg_types))
773         {
774             error( "Too many arguments in stdcall function '%s'\n", odp->name );
775             return 0;
776         }
777         for (i = 0; i < args; i++) odp->u.func.arg_types[i] = 'l';
778     }
779
780     /* check for optional internal name */
781
782     if (token && !strcmp( token, "=" ))
783     {
784         if (!(token = GetToken(0))) goto error;
785         odp->link_name = xstrdup( token );
786         remove_stdcall_decoration( odp->link_name );
787         token = GetToken(1);
788     }
789
790     /* check for optional ordinal */
791
792     if (token && token[0] == '@')
793     {
794         int ordinal;
795
796         if (!IsNumberString( token+1 ))
797         {
798             error( "Expected number after '@', got '%s'\n", token+1 );
799             goto error;
800         }
801         ordinal = atoi( token+1 );
802         if (!ordinal)
803         {
804             error( "Ordinal 0 is not valid\n" );
805             goto error;
806         }
807         if (ordinal >= MAX_ORDINALS)
808         {
809             error( "Ordinal number %d too large\n", ordinal );
810             goto error;
811         }
812         if (ordinal > spec->limit) spec->limit = ordinal;
813         if (ordinal < spec->base) spec->base = ordinal;
814         odp->ordinal = ordinal;
815         token = GetToken(1);
816     }
817
818     /* check for other optional keywords */
819
820     if (token && !strcmp( token, "NONAME" ))
821     {
822         if (odp->ordinal == -1)
823         {
824             error( "NONAME requires an ordinal\n" );
825             goto error;
826         }
827         odp->export_name = odp->name;
828         odp->name = NULL;
829         odp->flags |= FLAG_NONAME;
830         token = GetToken(1);
831     }
832     if (token && !strcmp( token, "PRIVATE" ))
833     {
834         odp->flags |= FLAG_PRIVATE;
835         token = GetToken(1);
836     }
837     if (token && !strcmp( token, "DATA" ))
838     {
839         odp->type = TYPE_EXTERN;
840         token = GetToken(1);
841     }
842     if (token)
843     {
844         error( "Garbage text '%s' found at end of export declaration\n", token );
845         goto error;
846     }
847     return 1;
848
849 error:
850     spec->nb_entry_points--;
851     free( odp->name );
852     return 0;
853 }
854
855
856 /*******************************************************************
857  *         parse_def_file
858  *
859  * Parse a .def file.
860  */
861 int parse_def_file( FILE *file, DLLSPEC *spec )
862 {
863     const char *token;
864     int in_exports = 0;
865
866     input_file = file;
867     current_line = 0;
868
869     comment_chars = ";";
870     separator_chars = ",=";
871
872     while (get_next_line())
873     {
874         if (!(token = GetToken(1))) continue;
875
876         if (!strcmp( token, "LIBRARY" ) || !strcmp( token, "NAME" ))
877         {
878             if (!parse_def_library( spec )) continue;
879             goto end_of_line;
880         }
881         else if (!strcmp( token, "STACKSIZE" ))
882         {
883             if (!parse_def_stack_heap_size( 1, spec )) continue;
884             goto end_of_line;
885         }
886         else if (!strcmp( token, "HEAPSIZE" ))
887         {
888             if (!parse_def_stack_heap_size( 0, spec )) continue;
889             goto end_of_line;
890         }
891         else if (!strcmp( token, "EXPORTS" ))
892         {
893             in_exports = 1;
894             if (!(token = GetToken(1))) continue;
895         }
896         else if (!strcmp( token, "IMPORTS" ))
897         {
898             in_exports = 0;
899             if (!(token = GetToken(1))) continue;
900         }
901         else if (!strcmp( token, "SECTIONS" ))
902         {
903             in_exports = 0;
904             if (!(token = GetToken(1))) continue;
905         }
906
907         if (!in_exports) continue;  /* ignore this line */
908         if (!parse_def_export( xstrdup(token), spec )) continue;
909
910     end_of_line:
911         if ((token = GetToken(1))) error( "Syntax error near '%s'\n", token );
912     }
913
914     current_line = 0;  /* no longer parsing the input file */
915     assign_names( spec );
916     assign_ordinals( spec );
917     return !nb_errors;
918 }
919
920
921 /*******************************************************************
922  *         add_debug_channel
923  */
924 static void add_debug_channel( const char *name )
925 {
926     int i;
927
928     for (i = 0; i < nb_debug_channels; i++)
929         if (!strcmp( debug_channels[i], name )) return;
930
931     debug_channels = xrealloc( debug_channels, (nb_debug_channels + 1) * sizeof(*debug_channels));
932     debug_channels[nb_debug_channels++] = xstrdup(name);
933 }
934
935
936 /*******************************************************************
937  *         parse_debug_channels
938  *
939  * Parse a source file and extract the debug channel definitions.
940  */
941 int parse_debug_channels( const char *srcdir, const char *filename )
942 {
943     FILE *file;
944     int eol_seen = 1;
945
946     file = open_input_file( srcdir, filename );
947     while (fgets( ParseBuffer, sizeof(ParseBuffer), file ))
948     {
949         char *channel, *end, *p = ParseBuffer;
950
951         p = ParseBuffer + strlen(ParseBuffer) - 1;
952         if (!eol_seen)  /* continuation line */
953         {
954             eol_seen = (*p == '\n');
955             continue;
956         }
957         if ((eol_seen = (*p == '\n'))) *p = 0;
958
959         p = ParseBuffer;
960         while (isspace(*p)) p++;
961         if (!memcmp( p, "WINE_DECLARE_DEBUG_CHANNEL", 26 ) ||
962             !memcmp( p, "WINE_DEFAULT_DEBUG_CHANNEL", 26 ))
963         {
964             p += 26;
965             while (isspace(*p)) p++;
966             if (*p != '(')
967             {
968                 error( "invalid debug channel specification '%s'\n", ParseBuffer );
969                 goto next;
970             }
971             p++;
972             while (isspace(*p)) p++;
973             if (!isalpha(*p))
974             {
975                 error( "invalid debug channel specification '%s'\n", ParseBuffer );
976                 goto next;
977             }
978             channel = p;
979             while (isalnum(*p) || *p == '_') p++;
980             end = p;
981             while (isspace(*p)) p++;
982             if (*p != ')')
983             {
984                 error( "invalid debug channel specification '%s'\n", ParseBuffer );
985                 goto next;
986             }
987             *end = 0;
988             add_debug_channel( channel );
989         }
990     next:
991         current_line++;
992     }
993     close_input_file( file );
994     return !nb_errors;
995 }