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