source: trunk/tools/pebuild/parser.c@ 10298

Last change on this file since 10298 was 10298, checked in by sandervl, 22 years ago

added

File size: 18.5 KB
Line 
1/*
2 * Spec file parser
3 *
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
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
39int current_line = 0;
40
41static char ParseBuffer[512];
42static char TokenBuffer[512];
43static char *ParseNext = ParseBuffer;
44static FILE *input_file;
45
46static const char * const TypeNames[TYPE_NBTYPES] =
47{
48 "variable", /* TYPE_VARIABLE */
49 "pascal", /* TYPE_PASCAL */
50 "equate", /* TYPE_ABS */
51 "stub", /* TYPE_STUB */
52 "stdcall", /* TYPE_STDCALL */
53 "cdecl", /* TYPE_CDECL */
54 "varargs", /* TYPE_VARARGS */
55 "extern" /* TYPE_EXTERN */
56};
57
58static const char * const FlagNames[] =
59{
60 "norelay", /* FLAG_NORELAY */
61 "noname", /* FLAG_NONAME */
62 "ret16", /* FLAG_RET16 */
63 "ret64", /* FLAG_RET64 */
64 "i386", /* FLAG_I386 */
65 "register", /* FLAG_REGISTER */
66 "interrupt", /* FLAG_INTERRUPT */
67 "private", /* FLAG_PRIVATE */
68 NULL
69};
70
71static int IsNumberString(const char *s)
72{
73 while (*s) if (!isdigit(*s++)) return 0;
74 return 1;
75}
76
77inline static int is_token_separator( char ch )
78{
79 return (ch == '(' || ch == ')' || ch == '-');
80}
81
82/* get the next line from the input file, or return 0 if at eof */
83static int get_next_line(void)
84{
85 ParseNext = ParseBuffer;
86 current_line++;
87 return (fgets(ParseBuffer, sizeof(ParseBuffer), input_file) != NULL);
88}
89
90static const char * GetToken( int allow_eol )
91{
92 char *p = ParseNext;
93 char *token = TokenBuffer;
94
95 for (;;)
96 {
97 /* remove initial white space */
98 p = ParseNext;
99 while (isspace(*p)) p++;
100
101 if (*p == '\\' && p[1] == '\n') /* line continuation */
102 {
103 if (!get_next_line())
104 {
105 if (!allow_eol) error( "Unexpected end of file\n" );
106 return NULL;
107 }
108 }
109 else break;
110 }
111
112 if ((*p == '\0') || (*p == '#'))
113 {
114 if (!allow_eol) error( "Declaration not terminated properly\n" );
115 return NULL;
116 }
117
118 /*
119 * Find end of token.
120 */
121 if (is_token_separator(*p))
122 {
123 /* a separator is always a complete token */
124 *token++ = *p++;
125 }
126 else while (*p != '\0' && !is_token_separator(*p) && !isspace(*p))
127 {
128 if (*p == '\\') p++;
129 if (*p) *token++ = *p++;
130 }
131 *token = '\0';
132 ParseNext = p;
133 return TokenBuffer;
134}
135
136
137/*******************************************************************
138 * ParseVariable
139 *
140 * Parse a variable definition.
141 */
142static int ParseVariable( ORDDEF *odp )
143{
144 char *endptr;
145 int *value_array;
146 int n_values;
147 int value_array_size;
148 const char *token;
149
150 if (SpecType == SPEC_WIN32)
151 {
152 error( "'variable' not supported in Win32, use 'extern' instead\n" );
153 return 0;
154 }
155
156 if (!(token = GetToken(0))) return 0;
157 if (*token != '(')
158 {
159 error( "Expected '(' got '%s'\n", token );
160 return 0;
161 }
162
163 n_values = 0;
164 value_array_size = 25;
165 value_array = xmalloc(sizeof(*value_array) * value_array_size);
166
167 for (;;)
168 {
169 if (!(token = GetToken(0)))
170 {
171 free( value_array );
172 return 0;
173 }
174 if (*token == ')')
175 break;
176
177 value_array[n_values++] = strtol(token, &endptr, 0);
178 if (n_values == value_array_size)
179 {
180 value_array_size += 25;
181 value_array = xrealloc(value_array,
182 sizeof(*value_array) * value_array_size);
183 }
184
185 if (endptr == NULL || *endptr != '\0')
186 {
187 error( "Expected number value, got '%s'\n", token );
188 free( value_array );
189 return 0;
190 }
191 }
192
193 odp->u.var.n_values = n_values;
194 odp->u.var.values = xrealloc(value_array, sizeof(*value_array) * n_values);
195 return 1;
196}
197
198
199/*******************************************************************
200 * ParseExportFunction
201 *
202 * Parse a function definition.
203 */
204static int ParseExportFunction( ORDDEF *odp )
205{
206 const char *token;
207 unsigned int i;
208
209 switch(SpecType)
210 {
211 case SPEC_WIN16:
212 if (odp->type == TYPE_STDCALL)
213 {
214 error( "'stdcall' not supported for Win16\n" );
215 return 0;
216 }
217 break;
218 case SPEC_WIN32:
219 if (odp->type == TYPE_PASCAL)
220 {
221 error( "'pascal' not supported for Win32\n" );
222 return 0;
223 }
224 if (odp->flags & FLAG_INTERRUPT)
225 {
226 error( "'interrupt' not supported for Win32\n" );
227 return 0;
228 }
229 break;
230 default:
231 break;
232 }
233
234 if (!(token = GetToken(0))) return 0;
235 if (*token != '(')
236 {
237 error( "Expected '(' got '%s'\n", token );
238 return 0;
239 }
240
241 for (i = 0; i < sizeof(odp->u.func.arg_types); i++)
242 {
243 if (!(token = GetToken(0))) return 0;
244 if (*token == ')')
245 break;
246
247 if (!strcmp(token, "word"))
248 odp->u.func.arg_types[i] = 'w';
249 else if (!strcmp(token, "s_word"))
250 odp->u.func.arg_types[i] = 's';
251 else if (!strcmp(token, "long") || !strcmp(token, "segptr"))
252 odp->u.func.arg_types[i] = 'l';
253 else if (!strcmp(token, "ptr"))
254 odp->u.func.arg_types[i] = 'p';
255 else if (!strcmp(token, "str"))
256 odp->u.func.arg_types[i] = 't';
257 else if (!strcmp(token, "wstr"))
258 odp->u.func.arg_types[i] = 'W';
259 else if (!strcmp(token, "segstr"))
260 odp->u.func.arg_types[i] = 'T';
261 else if (!strcmp(token, "double"))
262 {
263 odp->u.func.arg_types[i++] = 'l';
264 if (i < sizeof(odp->u.func.arg_types)) odp->u.func.arg_types[i] = 'l';
265 }
266 else
267 {
268 error( "Unknown argument type '%s'\n", token );
269 return 0;
270 }
271
272 if (SpecType == SPEC_WIN32)
273 {
274 if (strcmp(token, "long") &&
275 strcmp(token, "ptr") &&
276 strcmp(token, "str") &&
277 strcmp(token, "wstr") &&
278 strcmp(token, "double"))
279 {
280 error( "Type '%s' not supported for Win32\n", token );
281 return 0;
282 }
283 }
284 }
285 if ((*token != ')') || (i >= sizeof(odp->u.func.arg_types)))
286 {
287 error( "Too many arguments\n" );
288 return 0;
289 }
290
291 odp->u.func.arg_types[i] = '\0';
292 if (odp->type == TYPE_VARARGS)
293 odp->flags |= FLAG_NORELAY; /* no relay debug possible for varags entry point */
294
295 if (!(token = GetToken(1)))
296 {
297 if (!strcmp( odp->name, "@" ))
298 {
299 error( "Missing handler name for anonymous function\n" );
300 return 0;
301 }
302 odp->link_name = xstrdup( odp->name );
303 }
304 else
305 {
306 odp->link_name = xstrdup( token );
307 if (strchr( odp->link_name, '.' ))
308 {
309 if (SpecType == SPEC_WIN16)
310 {
311 error( "Forwarded functions not supported for Win16\n" );
312 return 0;
313 }
314 odp->flags |= FLAG_FORWARD;
315 }
316 }
317 return 1;
318}
319
320
321/*******************************************************************
322 * ParseEquate
323 *
324 * Parse an 'equate' definition.
325 */
326static int ParseEquate( ORDDEF *odp )
327{
328 char *endptr;
329 int value;
330 const char *token;
331
332 if (SpecType == SPEC_WIN32)
333 {
334 error( "'equate' not supported for Win32\n" );
335 return 0;
336 }
337 if (!(token = GetToken(0))) return 0;
338 value = strtol(token, &endptr, 0);
339 if (endptr == NULL || *endptr != '\0')
340 {
341 error( "Expected number value, got '%s'\n", token );
342 return 0;
343 }
344 odp->u.abs.value = value;
345 return 1;
346}
347
348
349/*******************************************************************
350 * ParseStub
351 *
352 * Parse a 'stub' definition.
353 */
354static int ParseStub( ORDDEF *odp )
355{
356 odp->u.func.arg_types[0] = '\0';
357 odp->link_name = xstrdup("");
358 return 1;
359}
360
361
362/*******************************************************************
363 * ParseExtern
364 *
365 * Parse an 'extern' definition.
366 */
367static int ParseExtern( ORDDEF *odp )
368{
369 const char *token;
370
371 if (SpecType == SPEC_WIN16)
372 {
373 error( "'extern' not supported for Win16, use 'variable' instead\n" );
374 return 0;
375 }
376 if (!(token = GetToken(1)))
377 {
378 if (!strcmp( odp->name, "@" ))
379 {
380 error( "Missing handler name for anonymous extern\n" );
381 return 0;
382 }
383 odp->link_name = xstrdup( odp->name );
384 }
385 else
386 {
387 odp->link_name = xstrdup( token );
388 if (strchr( odp->link_name, '.' )) odp->flags |= FLAG_FORWARD;
389 }
390 return 1;
391}
392
393
394/*******************************************************************
395 * ParseFlags
396 *
397 * Parse the optional flags for an entry point
398 */
399static const char *ParseFlags( ORDDEF *odp )
400{
401 unsigned int i;
402 const char *token;
403
404 do
405 {
406 if (!(token = GetToken(0))) break;
407 for (i = 0; FlagNames[i]; i++)
408 if (!strcmp( FlagNames[i], token )) break;
409 if (!FlagNames[i])
410 {
411 error( "Unknown flag '%s'\n", token );
412 return NULL;
413 }
414 odp->flags |= 1 << i;
415 token = GetToken(0);
416 } while (token && *token == '-');
417
418 return token;
419}
420
421/*******************************************************************
422 * fix_export_name
423 *
424 * Fix an exported function name by removing a possible @xx suffix
425 */
426static void fix_export_name( char *name )
427{
428 char *p, *end = strrchr( name, '@' );
429 if (!end || !end[1] || end == name) return;
430 /* make sure all the rest is digits */
431 for (p = end + 1; *p; p++) if (!isdigit(*p)) return;
432 *end = 0;
433}
434
435/*******************************************************************
436 * ParseOrdinal
437 *
438 * Parse an ordinal definition.
439 */
440static int ParseOrdinal(char *token, int ordinal)
441{
442 int len, fNameExport = FALSE;
443 ORDDEF *odp = xmalloc( sizeof(*odp) );
444 memset( odp, 0, sizeof(*odp) );
445 EntryPoints[nb_entry_points++] = odp;
446
447 odp->type = TYPE_STDCALL;
448
449 if (strstr(ParseNext, "NONAME")) {
450 odp->flags = FLAG_NONAME;
451 if(token[0] == '\"') {
452 int len = strlen(token+1);
453 token++;
454 if(token[len-1] == '\"') token[len-1] = 0;
455 }
456
457 odp->link_name = xstrdup( token );
458 len = strlen(odp->link_name);
459 if(odp->link_name[len-1] == '=') {
460 odp->link_name[len-1] = 0;
461 fNameExport = TRUE;
462 }
463 if(!fNameExport) token = GetToken(1);
464
465 if(fNameExport || (token && *token == '=')) {
466 token = GetToken(1);
467 if(token && token[0] == '\"') {
468 int len = strlen(token+1);
469 token++;
470 if(token[len-1] == '\"') token[len-1] = 0;
471 }
472 if(token) odp->link_name = xstrdup(token);
473 }
474 }
475 else
476 {
477 if(token[0] == '\"') {
478 int len = strlen(token+1);
479 token++;
480 if(token[len-1] == '\"') token[len-1] = 0;
481 }
482 odp->name = xstrdup( token );
483 len = strlen(odp->name);
484 if(odp->name[len-1] == '=') {
485 odp->name[len-1] = 0;
486 fNameExport = TRUE;
487 }
488 if(!fNameExport) token = GetToken(1);
489
490 if(fNameExport || (token && *token == '=')) {
491 token = GetToken(1);
492 if(token && token[0] == '\"') {
493 int len = strlen(token+1);
494 token++;
495 if(token[len-1] == '\"') token[len-1] = 0;
496 }
497 if(token) odp->link_name = xstrdup(token);
498 }
499 else odp->link_name = odp->name;
500
501 fix_export_name( odp->name );
502 }
503 odp->lineno = current_line;
504 odp->ordinal = ordinal;
505
506 if (!ordinal)
507 {
508 error( "Ordinal 0 is not valid\n" );
509 goto error;
510 }
511 if (ordinal >= MAX_ORDINALS)
512 {
513 error( "Ordinal number %d too large\n", ordinal );
514 goto error;
515 }
516 if (ordinal > Limit) Limit = ordinal;
517 if (ordinal < Base) Base = ordinal;
518 odp->ordinal = ordinal;
519 if (Ordinals[ordinal])
520 {
521 error( "Duplicate ordinal %d\n", ordinal );
522 goto error;
523 }
524 Ordinals[ordinal] = odp;
525
526
527 if (odp->flags & FLAG_NONAME)
528 {
529 if (ordinal == -1)
530 {
531 error( "Nameless function needs an explicit ordinal number\n" );
532 goto error;
533 }
534 if (SpecType != SPEC_WIN32)
535 {
536 error( "Nameless functions not supported for Win16\n" );
537 goto error;
538 }
539 odp->name = NULL;
540 }
541 else Names[nb_names++] = odp;
542 return 1;
543
544error:
545 EntryPoints[--nb_entry_points] = NULL;
546 free( odp->name );
547 free( odp );
548 return 0;
549}
550
551
552static int name_compare( const void *name1, const void *name2 )
553{
554 ORDDEF *odp1 = *(ORDDEF **)name1;
555 ORDDEF *odp2 = *(ORDDEF **)name2;
556 return strcmp( odp1->name, odp2->name );
557}
558
559/*******************************************************************
560 * sort_names
561 *
562 * Sort the name array and catch duplicates.
563 */
564static void sort_names(void)
565{
566 int i;
567
568 if (!nb_names) return;
569
570 /* sort the list of names */
571 qsort( Names, nb_names, sizeof(Names[0]), name_compare );
572
573 /* check for duplicate names */
574 for (i = 0; i < nb_names - 1; i++)
575 {
576 if (!strcmp( Names[i]->name, Names[i+1]->name ))
577 {
578 current_line = max( Names[i]->lineno, Names[i+1]->lineno );
579 error( "'%s' redefined\n%s:%d: First defined here\n",
580 Names[i]->name, input_file_name,
581 min( Names[i]->lineno, Names[i+1]->lineno ) );
582 }
583 }
584}
585
586
587/*******************************************************************
588 * ParseTopLevel
589 *
590 * Parse a spec file.
591 */
592char hextab[]="0123456789ABCDEF";
593
594int ParseTopLevel( FILE *file )
595{
596 const char *token, *ordinal, *tmp;
597 int ord, i, j, val, k;
598
599 input_file = file;
600 current_line = 0;
601
602 while (get_next_line()) {
603 if (!(token = GetToken(1))) continue;
604 if(strstr(token, "EXPORT")) break;
605 }
606
607 while (get_next_line())
608 {
609 if (!(token = GetToken(1))) continue;
610 if (token[0] == ';') {
611 if (!(token = GetToken(1))) continue;
612 if(!strcmp(token, "ENDOFEXPORTS")) break; //end of export section
613 continue; //comment
614 }
615
616 ordinal = strstr(ParseNext, "@");
617 if(ordinal == NULL) continue;
618 ordinal++;
619 tmp = strstr(ordinal, "@");
620 if(tmp && (tmp[1] >= '0' && tmp[1] <= '9')) ordinal = tmp+1;
621
622 while(*ordinal == ' ') ordinal++;
623
624 strupr(ordinal);
625
626 if(ordinal[0] == '0' && ordinal[1] == 'X')
627 {//hex ordinal
628 int len = strlen(ordinal)-2;
629
630 ordinal = ordinal+2;
631 ord = 0;
632 if(ordinal[len-1] == '\n') len -= 1;
633
634 for(i=0;i<len;i++) {
635 for(j=0;j<16;j++) {
636 if(hextab[j] == ordinal[i]) break;
637 }
638 if(j==16) {
639 printf("invalid hex number %s\n", ordinal);
640 exit(666);
641 }
642 val = 1;
643 for(k=0;k<len-i-1;k++) {
644 val *= 16;
645 }
646 ord += j*val;
647 }
648 }
649 else ord = atoi(ordinal);
650
651 if (!ParseOrdinal( token, ord )) continue;
652 }
653
654 current_line = 0; /* no longer parsing the input file */
655 sort_names();
656 return !nb_errors;
657}
658
659
660/*******************************************************************
661 * add_debug_channel
662 */
663static void add_debug_channel( const char *name )
664{
665 int i;
666
667 for (i = 0; i < nb_debug_channels; i++)
668 if (!strcmp( debug_channels[i], name )) return;
669
670 debug_channels = xrealloc( debug_channels, (nb_debug_channels + 1) * sizeof(*debug_channels));
671 debug_channels[nb_debug_channels++] = xstrdup(name);
672}
673
674
675/*******************************************************************
676 * parse_debug_channels
677 *
678 * Parse a source file and extract the debug channel definitions.
679 */
680int parse_debug_channels( const char *srcdir, const char *filename )
681{
682 FILE *file;
683 int eol_seen = 1;
684
685 file = open_input_file( srcdir, filename );
686 while (fgets( ParseBuffer, sizeof(ParseBuffer), file ))
687 {
688 char *channel, *end, *p = ParseBuffer;
689
690 p = ParseBuffer + strlen(ParseBuffer) - 1;
691 if (!eol_seen) /* continuation line */
692 {
693 eol_seen = (*p == '\n');
694 continue;
695 }
696 if ((eol_seen = (*p == '\n'))) *p = 0;
697
698 p = ParseBuffer;
699 while (isspace(*p)) p++;
700 if (!memcmp( p, "WINE_DECLARE_DEBUG_CHANNEL", 26 ) ||
701 !memcmp( p, "WINE_DEFAULT_DEBUG_CHANNEL", 26 ))
702 {
703 p += 26;
704 while (isspace(*p)) p++;
705 if (*p != '(')
706 {
707 error( "invalid debug channel specification '%s'\n", ParseBuffer );
708 goto next;
709 }
710 p++;
711 while (isspace(*p)) p++;
712 if (!isalpha(*p))
713 {
714 error( "invalid debug channel specification '%s'\n", ParseBuffer );
715 goto next;
716 }
717 channel = p;
718 while (isalnum(*p) || *p == '_') p++;
719 end = p;
720 while (isspace(*p)) p++;
721 if (*p != ')')
722 {
723 error( "invalid debug channel specification '%s'\n", ParseBuffer );
724 goto next;
725 }
726 *end = 0;
727 add_debug_channel( channel );
728 }
729 next:
730 current_line++;
731 }
732 close_input_file( file );
733 return !nb_errors;
734}
Note: See TracBrowser for help on using the repository browser.