Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/tools/winebuild/parser.c
8602 views
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
27
#include <assert.h>
28
#include <ctype.h>
29
#include <stdarg.h>
30
#include <stdio.h>
31
#include <stdlib.h>
32
#include <string.h>
33
34
#include "build.h"
35
36
int current_line = 0;
37
38
static char ParseBuffer[512];
39
static char TokenBuffer[512];
40
static char *ParseNext = ParseBuffer;
41
static FILE *input_file;
42
43
static const char *separator_chars;
44
static const char *comment_chars;
45
46
/* valid characters in ordinal names */
47
static const char valid_ordname_chars[] = "/$:-_@?<>abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
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
"register", /* FLAG_REGISTER */
68
"private", /* FLAG_PRIVATE */
69
"ordinal", /* FLAG_ORDINAL */
70
"thiscall", /* FLAG_THISCALL */
71
"fastcall", /* FLAG_FASTCALL */
72
"syscall", /* FLAG_SYSCALL */
73
"import", /* FLAG_IMPORT */
74
NULL
75
};
76
77
static const char * const ArgNames[ARG_MAXARG + 1] =
78
{
79
"word", /* ARG_WORD */
80
"s_word", /* ARG_SWORD */
81
"segptr", /* ARG_SEGPTR */
82
"segstr", /* ARG_SEGSTR */
83
"long", /* ARG_LONG */
84
"ptr", /* ARG_PTR */
85
"str", /* ARG_STR */
86
"wstr", /* ARG_WSTR */
87
"int64", /* ARG_INT64 */
88
"int128", /* ARG_INT128 */
89
"float", /* ARG_FLOAT */
90
"double" /* ARG_DOUBLE */
91
};
92
93
static int IsNumberString(const char *s)
94
{
95
while (*s) if (!isdigit(*s++)) return 0;
96
return 1;
97
}
98
99
static inline int is_token_separator( char ch )
100
{
101
return strchr( separator_chars, ch ) != NULL;
102
}
103
104
static inline int is_token_comment( char ch )
105
{
106
return strchr( comment_chars, ch ) != NULL;
107
}
108
109
/* get the next line from the input file, or return 0 if at eof */
110
static int get_next_line(void)
111
{
112
ParseNext = ParseBuffer;
113
current_line++;
114
return (fgets(ParseBuffer, sizeof(ParseBuffer), input_file) != NULL);
115
}
116
117
static const char * GetToken( int allow_eol )
118
{
119
char *p;
120
char *token = TokenBuffer;
121
122
for (;;)
123
{
124
/* remove initial white space */
125
p = ParseNext;
126
while (isspace(*p)) p++;
127
128
if (*p == '\\' && p[1] == '\n') /* line continuation */
129
{
130
if (!get_next_line())
131
{
132
if (!allow_eol) error( "Unexpected end of file\n" );
133
return NULL;
134
}
135
}
136
else break;
137
}
138
139
if ((*p == '\0') || is_token_comment(*p))
140
{
141
if (!allow_eol) error( "Declaration not terminated properly\n" );
142
return NULL;
143
}
144
145
/*
146
* Find end of token.
147
*/
148
if (is_token_separator(*p))
149
{
150
/* a separator is always a complete token */
151
*token++ = *p++;
152
}
153
else while (*p != '\0' && !is_token_separator(*p) && !isspace(*p))
154
{
155
if (*p == '\\') p++;
156
if (*p) *token++ = *p++;
157
}
158
*token = '\0';
159
ParseNext = p;
160
return TokenBuffer;
161
}
162
163
164
static ORDDEF *add_entry_point( DLLSPEC *spec )
165
{
166
ORDDEF *ret = ARRAY_ADD( &spec->entry_points, ORDDEF );
167
168
memset( ret, 0, sizeof(*ret) );
169
return ret;
170
}
171
172
/*******************************************************************
173
* parse_spec_variable
174
*
175
* Parse a variable definition in a .spec file.
176
*/
177
static int parse_spec_variable( ORDDEF *odp, DLLSPEC *spec )
178
{
179
char *endptr;
180
const char *token;
181
struct array values = empty_array;
182
183
if (spec->type == SPEC_WIN32)
184
{
185
error( "'variable' not supported in Win32, use 'extern' instead\n" );
186
return 0;
187
}
188
189
if (!(token = GetToken(0))) return 0;
190
if (*token != '(')
191
{
192
error( "Expected '(' got '%s'\n", token );
193
return 0;
194
}
195
196
for (;;)
197
{
198
if (!(token = GetToken(0))) return 0;
199
if (*token == ')') break;
200
201
*ARRAY_ADD( &values, unsigned int ) = strtoul(token, &endptr, 0);
202
if (endptr == NULL || *endptr != '\0')
203
{
204
error( "Expected number value, got '%s'\n", token );
205
return 0;
206
}
207
}
208
209
odp->u.var = values;
210
return 1;
211
}
212
213
214
/*******************************************************************
215
* parse_spec_arguments
216
*
217
* Parse the arguments of an entry point.
218
*/
219
static int parse_spec_arguments( ORDDEF *odp, DLLSPEC *spec, int optional )
220
{
221
const char *token;
222
unsigned int i, arg;
223
int is_win32 = (spec->type == SPEC_WIN32) || (odp->flags & FLAG_EXPORT32);
224
225
odp->u.func.nb_args = 0;
226
227
if (!(token = GetToken( optional ))) return optional;
228
if (*token != '(')
229
{
230
error( "Expected '(' got '%s'\n", token );
231
return 0;
232
}
233
234
for (i = 0; i < MAX_ARGUMENTS; i++)
235
{
236
if (!(token = GetToken(0))) return 0;
237
if (*token == ')')
238
break;
239
240
for (arg = 0; arg <= ARG_MAXARG; arg++)
241
if (!strcmp( ArgNames[arg], token )) break;
242
243
if (arg > ARG_MAXARG)
244
{
245
error( "Unknown argument type '%s'\n", token );
246
return 0;
247
}
248
switch (arg)
249
{
250
case ARG_WORD:
251
case ARG_SWORD:
252
case ARG_SEGPTR:
253
case ARG_SEGSTR:
254
if (!is_win32) break;
255
error( "Argument type '%s' only allowed for Win16\n", token );
256
return 0;
257
case ARG_INT64:
258
case ARG_INT128:
259
case ARG_FLOAT:
260
case ARG_DOUBLE:
261
if (!(odp->flags & FLAG_SYSCALL)) break;
262
error( "Argument type '%s' not allowed for syscall function\n", token );
263
return 0;
264
}
265
odp->u.func.args[i] = arg;
266
}
267
if (*token != ')')
268
{
269
error( "Too many arguments\n" );
270
return 0;
271
}
272
273
odp->u.func.nb_args = i;
274
if (odp->flags & FLAG_THISCALL)
275
{
276
if (odp->type != TYPE_STDCALL)
277
{
278
error( "A thiscall function must use the stdcall convention\n" );
279
return 0;
280
}
281
if (!i || odp->u.func.args[0] != ARG_PTR)
282
{
283
error( "First argument of a thiscall function must be a pointer\n" );
284
return 0;
285
}
286
if (odp->flags & FLAG_CPU_MASK & ~FLAG_CPU(CPU_i386))
287
{
288
error( "A thiscall function can only be exported on i386\n" );
289
return 0;
290
}
291
}
292
if (odp->flags & FLAG_FASTCALL)
293
{
294
if (odp->type != TYPE_STDCALL)
295
{
296
error( "A fastcall function must use the stdcall convention\n" );
297
return 0;
298
}
299
if ((i && odp->u.func.args[0] != ARG_PTR && odp->u.func.args[0] != ARG_LONG) ||
300
(i > 1 && odp->u.func.args[1] != ARG_PTR && odp->u.func.args[1] != ARG_LONG))
301
odp->flags |= FLAG_NORELAY; /* no relay debug possible for non-standard fastcall args */
302
}
303
if (odp->flags & FLAG_SYSCALL)
304
{
305
if (odp->type != TYPE_STDCALL && odp->type != TYPE_STUB)
306
{
307
error( "A syscall function must use the stdcall convention\n" );
308
return 0;
309
}
310
}
311
return 1;
312
}
313
314
315
/*******************************************************************
316
* parse_spec_export
317
*
318
* Parse an exported function definition in a .spec file.
319
*/
320
static int parse_spec_export( ORDDEF *odp, DLLSPEC *spec )
321
{
322
const char *token;
323
int is_win32 = (spec->type == SPEC_WIN32) || (odp->flags & FLAG_EXPORT32);
324
325
if (!is_win32 && odp->type == TYPE_STDCALL)
326
{
327
error( "'stdcall' not supported for Win16\n" );
328
return 0;
329
}
330
if (is_win32 && odp->type == TYPE_PASCAL)
331
{
332
error( "'pascal' not supported for Win32\n" );
333
return 0;
334
}
335
336
if (!parse_spec_arguments( odp, spec, 0 )) return 0;
337
338
if (odp->type == TYPE_VARARGS)
339
odp->flags |= FLAG_NORELAY; /* no relay debug possible for varags entry point */
340
341
if (target.cpu != CPU_i386)
342
odp->flags &= ~FLAG_FASTCALL;
343
344
if (!(token = GetToken(1)))
345
{
346
if (!strcmp( odp->name, "@" ))
347
{
348
error( "Missing handler name for anonymous function\n" );
349
return 0;
350
}
351
odp->link_name = xstrdup( odp->name );
352
}
353
else
354
{
355
odp->link_name = xstrdup( token );
356
if (strchr( odp->link_name, '.' ))
357
{
358
if (!is_win32)
359
{
360
error( "Forwarded functions not supported for Win16\n" );
361
return 0;
362
}
363
odp->flags |= FLAG_FORWARD;
364
}
365
}
366
return 1;
367
}
368
369
370
/*******************************************************************
371
* parse_spec_equate
372
*
373
* Parse an 'equate' definition in a .spec file.
374
*/
375
static int parse_spec_equate( ORDDEF *odp, DLLSPEC *spec )
376
{
377
char *endptr;
378
int value;
379
const char *token;
380
381
if (spec->type == SPEC_WIN32)
382
{
383
error( "'equate' not supported for Win32\n" );
384
return 0;
385
}
386
if (!(token = GetToken(0))) return 0;
387
value = strtol(token, &endptr, 0);
388
if (endptr == NULL || *endptr != '\0')
389
{
390
error( "Expected number value, got '%s'\n", token );
391
return 0;
392
}
393
if (value < -0x8000 || value > 0xffff)
394
{
395
error( "Value %d for absolute symbol doesn't fit in 16 bits\n", value );
396
value = 0;
397
}
398
odp->u.abs = value;
399
return 1;
400
}
401
402
403
/*******************************************************************
404
* parse_spec_stub
405
*
406
* Parse a 'stub' definition in a .spec file
407
*/
408
static int parse_spec_stub( ORDDEF *odp, DLLSPEC *spec )
409
{
410
const char *token;
411
412
if (!parse_spec_arguments( odp, spec, 1 )) return 0;
413
414
if (!(token = GetToken(1)))
415
odp->link_name = xstrdup( odp->name );
416
else
417
odp->link_name = xstrdup( token );
418
419
return 1;
420
}
421
422
423
/*******************************************************************
424
* parse_spec_extern
425
*
426
* Parse an 'extern' definition in a .spec file.
427
*/
428
static int parse_spec_extern( ORDDEF *odp, DLLSPEC *spec )
429
{
430
const char *token;
431
432
if (spec->type == SPEC_WIN16)
433
{
434
error( "'extern' not supported for Win16, use 'variable' instead\n" );
435
return 0;
436
}
437
if (!(token = GetToken(1)))
438
{
439
if (!strcmp( odp->name, "@" ))
440
{
441
error( "Missing handler name for anonymous extern\n" );
442
return 0;
443
}
444
odp->link_name = xstrdup( odp->name );
445
}
446
else
447
{
448
odp->link_name = xstrdup( token );
449
if (strchr( odp->link_name, '.' )) odp->flags |= FLAG_FORWARD;
450
}
451
return 1;
452
}
453
454
455
/*******************************************************************
456
* parse_spec_flags
457
*
458
* Parse the optional flags for an entry point in a .spec file.
459
*/
460
static const char *parse_spec_flags( DLLSPEC *spec, ORDDEF *odp, const char *token )
461
{
462
unsigned int i, cpu_mask = 0;
463
464
do
465
{
466
token++;
467
if (!strncmp( token, "arch=", 5))
468
{
469
char *args = xstrdup( token + 5 );
470
char *cpu_name = strtok( args, "," );
471
while (cpu_name)
472
{
473
if (!strcmp( cpu_name, "win32" ))
474
{
475
if (spec->type == SPEC_WIN32)
476
odp->flags |= FLAG_CPU_WIN32;
477
else
478
odp->flags |= FLAG_EXPORT32;
479
}
480
else if (!strcmp( cpu_name, "win64" ))
481
odp->flags |= FLAG_CPU_WIN64;
482
else
483
{
484
int cpu = get_cpu_from_name( cpu_name + (cpu_name[0] == '!') );
485
if (cpu == -1)
486
{
487
error( "Unknown architecture '%s'\n", cpu_name );
488
return NULL;
489
}
490
if (cpu_name[0] == '!') cpu_mask |= FLAG_CPU( cpu );
491
else odp->flags |= FLAG_CPU( cpu );
492
}
493
cpu_name = strtok( NULL, "," );
494
}
495
free( args );
496
}
497
else if (!strncmp( token, "syscall=", 8 ))
498
{
499
char *end;
500
unsigned int id = strtoul( token + 8, &end, 0 );
501
502
if (*end || id >= 0x4000)
503
error( "Invalid syscall number '%s', should be in range 0-0x3fff\n", token + 8 );
504
odp->flags |= FLAG_SYSCALL;
505
}
506
else if (!strcmp( token, "i386" )) /* backwards compatibility */
507
{
508
odp->flags |= FLAG_CPU(CPU_i386);
509
}
510
else
511
{
512
for (i = 0; FlagNames[i]; i++)
513
if (!strcmp( FlagNames[i], token )) break;
514
if (!FlagNames[i])
515
{
516
error( "Unknown flag '%s'\n", token );
517
return NULL;
518
}
519
switch (1 << i)
520
{
521
case FLAG_RET16:
522
case FLAG_REGISTER:
523
if (spec->type == SPEC_WIN32)
524
error( "Flag '%s' is not supported in Win32\n", FlagNames[i] );
525
break;
526
case FLAG_RET64:
527
case FLAG_THISCALL:
528
case FLAG_FASTCALL:
529
if (spec->type == SPEC_WIN16)
530
error( "Flag '%s' is not supported in Win16\n", FlagNames[i] );
531
break;
532
}
533
odp->flags |= 1 << i;
534
}
535
token = GetToken(0);
536
} while (token && *token == '-');
537
538
/* x86-64 implies arm64ec */
539
if (odp->flags & FLAG_CPU(CPU_x86_64)) odp->flags |= FLAG_CPU(CPU_ARM64EC);
540
if (cpu_mask & FLAG_CPU(CPU_x86_64)) cpu_mask |= FLAG_CPU(CPU_ARM64EC);
541
542
if (cpu_mask) odp->flags |= FLAG_CPU_MASK & ~cpu_mask;
543
return token;
544
}
545
546
547
/*******************************************************************
548
* parse_spec_ordinal
549
*
550
* Parse an ordinal definition in a .spec file.
551
*/
552
static int parse_spec_ordinal( int ordinal, DLLSPEC *spec )
553
{
554
const char *token;
555
size_t len;
556
ORDDEF *odp = add_entry_point( spec );
557
558
if (!(token = GetToken(0))) goto error;
559
560
for (odp->type = 0; odp->type < TYPE_NBTYPES; odp->type++)
561
if (TypeNames[odp->type] && !strcmp( token, TypeNames[odp->type] ))
562
break;
563
564
if (odp->type >= TYPE_NBTYPES)
565
{
566
if (!strcmp( token, "thiscall" )) /* for backwards compatibility */
567
{
568
odp->type = TYPE_STDCALL;
569
odp->flags |= FLAG_THISCALL;
570
}
571
else
572
{
573
error( "Expected type after ordinal, found '%s' instead\n", token );
574
goto error;
575
}
576
}
577
578
if (!(token = GetToken(0))) goto error;
579
if (*token == '-' && !(token = parse_spec_flags( spec, odp, token ))) goto error;
580
581
if (ordinal == -1 && spec->type != SPEC_WIN32 && !(odp->flags & FLAG_EXPORT32))
582
{
583
error( "'@' ordinals not supported for Win16\n" );
584
goto error;
585
}
586
587
odp->name = xstrdup( token );
588
odp->lineno = current_line;
589
odp->ordinal = ordinal;
590
591
len = strspn( odp->name, valid_ordname_chars );
592
if (len < strlen( odp->name ))
593
{
594
error( "Character '%c' is not allowed in exported name '%s'\n", odp->name[len], odp->name );
595
goto error;
596
}
597
598
switch(odp->type)
599
{
600
case TYPE_VARIABLE:
601
if (!parse_spec_variable( odp, spec )) goto error;
602
break;
603
case TYPE_PASCAL:
604
case TYPE_STDCALL:
605
case TYPE_VARARGS:
606
case TYPE_CDECL:
607
if (!parse_spec_export( odp, spec )) goto error;
608
break;
609
case TYPE_ABS:
610
if (!parse_spec_equate( odp, spec )) goto error;
611
break;
612
case TYPE_STUB:
613
if (!parse_spec_stub( odp, spec )) goto error;
614
break;
615
case TYPE_EXTERN:
616
if (!parse_spec_extern( odp, spec )) goto error;
617
break;
618
default:
619
assert( 0 );
620
}
621
622
if (data_only && !(odp->flags & FLAG_FORWARD))
623
{
624
error( "Only forwarded entry points are allowed in data-only mode\n" );
625
goto error;
626
}
627
628
if (ordinal != -1)
629
{
630
if (!ordinal)
631
{
632
error( "Ordinal 0 is not valid\n" );
633
goto error;
634
}
635
if (ordinal >= MAX_ORDINALS)
636
{
637
error( "Ordinal number %d too large\n", ordinal );
638
goto error;
639
}
640
odp->ordinal = ordinal;
641
}
642
643
if (odp->type == TYPE_STDCALL && !(odp->flags & FLAG_PRIVATE))
644
{
645
if (!strcmp( odp->name, "DllRegisterServer" ) ||
646
!strcmp( odp->name, "DllUnregisterServer" ) ||
647
!strcmp( odp->name, "DllMain" ) ||
648
!strcmp( odp->name, "DllGetClassObject" ) ||
649
!strcmp( odp->name, "DllGetVersion" ) ||
650
!strcmp( odp->name, "DllInstall" ) ||
651
!strcmp( odp->name, "DllCanUnloadNow" ))
652
{
653
warning( "Function %s should be marked private\n", odp->name );
654
if (strcmp( odp->name, odp->link_name ))
655
warning( "Function %s should not use a different internal name (%s)\n",
656
odp->name, odp->link_name );
657
}
658
}
659
660
if (!strcmp( odp->name, "@" ) || odp->flags & (FLAG_NONAME | FLAG_ORDINAL))
661
{
662
if (ordinal == -1)
663
{
664
if (!strcmp( odp->name, "@" ))
665
error( "Nameless function needs an explicit ordinal number\n" );
666
else
667
error( "Function imported by ordinal needs an explicit ordinal number\n" );
668
goto error;
669
}
670
if (spec->type != SPEC_WIN32)
671
{
672
error( "Nameless functions not supported for Win16\n" );
673
goto error;
674
}
675
if (!strcmp( odp->name, "@" ))
676
{
677
free( odp->name );
678
odp->name = NULL;
679
}
680
else if (!(odp->flags & FLAG_ORDINAL)) /* -ordinal only affects the import library */
681
{
682
odp->export_name = odp->name;
683
odp->name = NULL;
684
}
685
}
686
return 1;
687
688
error:
689
spec->entry_points.count--;
690
free( odp->name );
691
return 0;
692
}
693
694
695
static unsigned int apiset_hash_len( const char *str )
696
{
697
return strrchr( str, '-' ) - str;
698
}
699
700
static unsigned int apiset_hash( const char *str )
701
{
702
unsigned int ret = 0, len = apiset_hash_len( str );
703
while (len--) ret = ret * apiset_hash_factor + *str++;
704
return ret;
705
}
706
707
static unsigned int apiset_add_str( struct apiset *apiset, const char *str, unsigned int len )
708
{
709
char *ret;
710
711
if (!apiset->strings || !(ret = strstr( apiset->strings, str )))
712
{
713
if (apiset->str_pos + len >= apiset->str_size)
714
{
715
apiset->str_size = max( apiset->str_size * 2, 1024 );
716
apiset->strings = xrealloc( apiset->strings, apiset->str_size );
717
}
718
ret = apiset->strings + apiset->str_pos;
719
memcpy( ret, str, len );
720
ret[len] = 0;
721
apiset->str_pos += len;
722
}
723
return ret - apiset->strings;
724
}
725
726
static struct apiset_entry *add_apiset( struct apiset *apiset, const char *api )
727
{
728
struct apiset_entry *entry = ARRAY_ADD( &apiset->entries, struct apiset_entry );
729
730
entry->name_len = strlen( api );
731
entry->name_off = apiset_add_str( apiset, api, entry->name_len );
732
entry->hash = apiset_hash( api );
733
entry->hash_len = apiset_hash_len( api );
734
entry->val_count = 0;
735
return entry;
736
}
737
738
static void add_apiset_value( struct apiset *apiset, struct apiset_entry *entry, const char *value )
739
{
740
if (entry->val_count < ARRAY_SIZE(entry->values) - 1)
741
{
742
struct apiset_value *val = &entry->values[entry->val_count++];
743
char *sep = strchr( value, ':' );
744
745
if (sep)
746
{
747
val->name_len = sep - value;
748
val->name_off = apiset_add_str( apiset, value, val->name_len );
749
val->val_len = strlen( sep + 1 );
750
val->val_off = apiset_add_str( apiset, sep + 1, val->val_len );
751
}
752
else
753
{
754
val->name_len = val->name_off = 0;
755
val->val_len = strlen( value );
756
val->val_off = apiset_add_str( apiset, value, val->val_len );
757
}
758
}
759
else error( "Too many values for api '%.*s'\n", entry->name_len, apiset->strings + entry->name_off );
760
}
761
762
/*******************************************************************
763
* parse_spec_apiset
764
*/
765
static int parse_spec_apiset( DLLSPEC *spec )
766
{
767
struct apiset_entry *entry;
768
const char *token;
769
unsigned int hash;
770
771
if (!data_only)
772
{
773
error( "Apiset definitions are only allowed in data-only mode\n" );
774
return 0;
775
}
776
777
if (!(token = GetToken(0))) return 0;
778
779
if (!strncmp( token, "api-", 4 ) && !strncmp( token, "ext-", 4 ))
780
{
781
error( "Unrecognized API set name '%s'\n", token );
782
return 0;
783
}
784
785
hash = apiset_hash( token );
786
ARRAY_FOR_EACH( entry, &spec->apiset.entries, struct apiset_entry )
787
{
788
if (entry->name_len == strlen( token ) &&
789
!strncmp( spec->apiset.strings + entry->name_off, token, entry->name_len ))
790
{
791
error( "Duplicate API set '%s'\n", token );
792
return 0;
793
}
794
if (entry->hash == hash)
795
{
796
error( "Duplicate hash code '%.*s' and '%s'\n",
797
entry->name_len, spec->apiset.strings + entry->name_off, token );
798
return 0;
799
}
800
}
801
802
entry = add_apiset( &spec->apiset, token );
803
804
if (!(token = GetToken(0)) || strcmp( token, "=" ))
805
{
806
error( "Syntax error near '%s'\n", token );
807
return 0;
808
}
809
810
while ((token = GetToken(1))) add_apiset_value( &spec->apiset, entry, token );
811
return 1;
812
}
813
814
815
static int name_compare( const void *ptr1, const void *ptr2 )
816
{
817
const ORDDEF *odp1 = *(const ORDDEF * const *)ptr1;
818
const ORDDEF *odp2 = *(const ORDDEF * const *)ptr2;
819
const char *name1 = odp1->name ? odp1->name : odp1->export_name;
820
const char *name2 = odp2->name ? odp2->name : odp2->export_name;
821
return strcmp( name1, name2 );
822
}
823
824
/*******************************************************************
825
* assign_names
826
*
827
* Build the name array and catch duplicates.
828
*/
829
static void assign_names( struct exports *exports )
830
{
831
int i, j, nb_exp_names = 0;
832
ORDDEF **all_names;
833
834
exports->nb_names = 0;
835
for (i = 0; i < exports->nb_entry_points; i++)
836
if (exports->entry_points[i]->name) exports->nb_names++;
837
else if (exports->entry_points[i]->export_name) nb_exp_names++;
838
839
if (!exports->nb_names && !nb_exp_names) return;
840
841
/* check for duplicates */
842
843
all_names = xmalloc( (exports->nb_names + nb_exp_names) * sizeof(all_names[0]) );
844
for (i = j = 0; i < exports->nb_entry_points; i++)
845
if (exports->entry_points[i]->name || exports->entry_points[i]->export_name)
846
all_names[j++] = exports->entry_points[i];
847
848
qsort( all_names, j, sizeof(all_names[0]), name_compare );
849
850
for (i = 0; i < j - 1; i++)
851
{
852
const char *name1 = all_names[i]->name ? all_names[i]->name : all_names[i]->export_name;
853
const char *name2 = all_names[i+1]->name ? all_names[i+1]->name : all_names[i+1]->export_name;
854
if (!strcmp( name1, name2 ) &&
855
!((all_names[i]->flags ^ all_names[i+1]->flags) & FLAG_EXPORT32))
856
{
857
current_line = max( all_names[i]->lineno, all_names[i+1]->lineno );
858
error( "'%s' redefined\n%s:%d: First defined here\n",
859
name1, input_file_name,
860
min( all_names[i]->lineno, all_names[i+1]->lineno ) );
861
}
862
}
863
free( all_names );
864
865
if (exports->nb_names)
866
{
867
exports->names = xmalloc( exports->nb_names * sizeof(exports->names[0]) );
868
for (i = j = 0; i < exports->nb_entry_points; i++)
869
if (exports->entry_points[i]->name) exports->names[j++] = exports->entry_points[i];
870
871
/* sort the list of names */
872
qsort( exports->names, exports->nb_names, sizeof(exports->names[0]), name_compare );
873
for (i = 0; i < exports->nb_names; i++) exports->names[i]->hint = i;
874
}
875
}
876
877
/*******************************************************************
878
* assign_ordinals
879
*
880
* Build the ordinal array.
881
*/
882
static void assign_ordinals( struct exports *exports )
883
{
884
int i, count, ordinal;
885
886
/* start assigning from base, or from 1 if no ordinal defined yet */
887
888
exports->base = MAX_ORDINALS;
889
exports->limit = 0;
890
for (i = 0; i < exports->nb_entry_points; i++)
891
{
892
ordinal = exports->entry_points[i]->ordinal;
893
if (ordinal == -1) continue;
894
if (ordinal > exports->limit) exports->limit = ordinal;
895
if (ordinal < exports->base) exports->base = ordinal;
896
}
897
if (exports->base == MAX_ORDINALS) exports->base = 1;
898
if (exports->limit < exports->base) exports->limit = exports->base;
899
900
count = max( exports->limit + 1, exports->base + exports->nb_entry_points );
901
exports->ordinals = xmalloc( count * sizeof(exports->ordinals[0]) );
902
memset( exports->ordinals, 0, count * sizeof(exports->ordinals[0]) );
903
904
/* fill in all explicitly specified ordinals */
905
for (i = 0; i < exports->nb_entry_points; i++)
906
{
907
ordinal = exports->entry_points[i]->ordinal;
908
if (ordinal == -1) continue;
909
if (exports->ordinals[ordinal])
910
{
911
current_line = max( exports->entry_points[i]->lineno, exports->ordinals[ordinal]->lineno );
912
error( "ordinal %d redefined\n%s:%d: First defined here\n",
913
ordinal, input_file_name,
914
min( exports->entry_points[i]->lineno, exports->ordinals[ordinal]->lineno ) );
915
}
916
else exports->ordinals[ordinal] = exports->entry_points[i];
917
}
918
919
/* now assign ordinals to the rest */
920
for (i = 0, ordinal = exports->base; i < exports->nb_entry_points; i++)
921
{
922
if (exports->entry_points[i]->ordinal != -1) continue;
923
while (exports->ordinals[ordinal]) ordinal++;
924
if (ordinal >= MAX_ORDINALS)
925
{
926
current_line = exports->entry_points[i]->lineno;
927
fatal_error( "Too many functions defined (max %d)\n", MAX_ORDINALS );
928
}
929
exports->entry_points[i]->ordinal = ordinal;
930
exports->ordinals[ordinal] = exports->entry_points[i];
931
}
932
if (ordinal > exports->limit) exports->limit = ordinal;
933
}
934
935
936
static void assign_exports( DLLSPEC *spec, unsigned int cpu, struct exports *exports )
937
{
938
exports->entry_points = xmalloc( spec->entry_points.count * sizeof(*exports->entry_points) );
939
ARRAY_FOR_EACH( entry, &spec->entry_points, ORDDEF )
940
{
941
if ((entry->flags & FLAG_CPU_MASK) && !(entry->flags & FLAG_CPU(cpu)))
942
continue;
943
exports->entry_points[exports->nb_entry_points++] = entry;
944
}
945
946
assign_names( exports );
947
assign_ordinals( exports );
948
}
949
950
951
/*******************************************************************
952
* add_16bit_exports
953
*
954
* Add the necessary exports to the 32-bit counterpart of a 16-bit module.
955
*/
956
void add_16bit_exports( DLLSPEC *spec32, DLLSPEC *spec16 )
957
{
958
int i;
959
ORDDEF *odp;
960
961
spec32->file_name = xstrdup( spec16->file_name );
962
spec32->characteristics = IMAGE_FILE_DLL;
963
spec32->init_func = xstrdup( "DllMain" );
964
965
/* add an export for the NE module */
966
967
odp = add_entry_point( spec32 );
968
odp->type = TYPE_EXTERN;
969
odp->flags = FLAG_PRIVATE;
970
odp->name = xstrdup( "__wine_spec_dos_header" );
971
odp->lineno = 0;
972
odp->ordinal = 1;
973
odp->link_name = xstrdup( ".L__wine_spec_dos_header" );
974
975
if (spec16->main_module)
976
{
977
odp = add_entry_point( spec32 );
978
odp->type = TYPE_EXTERN;
979
odp->flags = FLAG_PRIVATE;
980
odp->name = xstrdup( "__wine_spec_main_module" );
981
odp->lineno = 0;
982
odp->ordinal = 2;
983
odp->link_name = xstrdup( ".L__wine_spec_main_module" );
984
}
985
986
/* add the explicit win32 exports */
987
988
for (i = 1; i <= spec16->exports.limit; i++)
989
{
990
ORDDEF *odp16 = spec16->exports.ordinals[i];
991
992
if (!odp16 || !odp16->name) continue;
993
if (!(odp16->flags & FLAG_EXPORT32)) continue;
994
995
odp = add_entry_point( spec32 );
996
odp->flags = odp16->flags & ~FLAG_EXPORT32;
997
odp->type = odp16->type;
998
odp->name = xstrdup( odp16->name );
999
odp->lineno = odp16->lineno;
1000
odp->ordinal = -1;
1001
odp->link_name = xstrdup( odp16->link_name );
1002
odp->u.func.nb_args = odp16->u.func.nb_args;
1003
if (odp->u.func.nb_args > 0) memcpy( odp->u.func.args, odp16->u.func.args,
1004
odp->u.func.nb_args * sizeof(odp->u.func.args[0]) );
1005
}
1006
1007
assign_exports( spec32, target.cpu, &spec32->exports );
1008
}
1009
1010
1011
/*******************************************************************
1012
* parse_spec_file
1013
*
1014
* Parse a .spec file.
1015
*/
1016
int parse_spec_file( FILE *file, DLLSPEC *spec )
1017
{
1018
const char *token;
1019
1020
input_file = file;
1021
current_line = 0;
1022
1023
comment_chars = "#;";
1024
separator_chars = "()";
1025
1026
while (get_next_line())
1027
{
1028
if (!(token = GetToken(1))) continue;
1029
if (strcmp(token, "@") == 0)
1030
{
1031
if (!parse_spec_ordinal( -1, spec )) continue;
1032
}
1033
else if (IsNumberString(token))
1034
{
1035
if (!parse_spec_ordinal( atoi(token), spec )) continue;
1036
}
1037
else if (strcmp(token, "apiset") == 0)
1038
{
1039
if (!parse_spec_apiset( spec )) continue;
1040
}
1041
else
1042
{
1043
error( "Expected ordinal declaration, got '%s'\n", token );
1044
continue;
1045
}
1046
if ((token = GetToken(1))) error( "Syntax error near '%s'\n", token );
1047
}
1048
1049
current_line = 0; /* no longer parsing the input file */
1050
assign_exports( spec, target.cpu, &spec->exports );
1051
if (native_arch != -1) assign_exports( spec, native_arch, &spec->native_exports );
1052
return !nb_errors;
1053
}
1054
1055
1056
/*******************************************************************
1057
* parse_def_library
1058
*
1059
* Parse a LIBRARY declaration in a .def file.
1060
*/
1061
static int parse_def_library( DLLSPEC *spec )
1062
{
1063
const char *token = GetToken(1);
1064
1065
if (!token) return 1;
1066
if (strcmp( token, "BASE" ))
1067
{
1068
free( spec->file_name );
1069
spec->file_name = xstrdup( token );
1070
if (!(token = GetToken(1))) return 1;
1071
}
1072
if (strcmp( token, "BASE" ))
1073
{
1074
error( "Expected library name or BASE= declaration, got '%s'\n", token );
1075
return 0;
1076
}
1077
if (!(token = GetToken(0))) return 0;
1078
if (strcmp( token, "=" ))
1079
{
1080
error( "Expected '=' after BASE, got '%s'\n", token );
1081
return 0;
1082
}
1083
if (!(token = GetToken(0))) return 0;
1084
/* FIXME: do something with base address */
1085
1086
return 1;
1087
}
1088
1089
1090
/*******************************************************************
1091
* parse_def_stack_heap_size
1092
*
1093
* Parse a STACKSIZE or HEAPSIZE declaration in a .def file.
1094
*/
1095
static int parse_def_stack_heap_size( int is_stack, DLLSPEC *spec )
1096
{
1097
const char *token = GetToken(0);
1098
char *end;
1099
unsigned long size;
1100
1101
if (!token) return 0;
1102
size = strtoul( token, &end, 0 );
1103
if (*end)
1104
{
1105
error( "Invalid number '%s'\n", token );
1106
return 0;
1107
}
1108
if (is_stack) spec->stack_size = size / 1024;
1109
else spec->heap_size = size / 1024;
1110
if (!(token = GetToken(1))) return 1;
1111
if (strcmp( token, "," ))
1112
{
1113
error( "Expected ',' after size, got '%s'\n", token );
1114
return 0;
1115
}
1116
if (!(token = GetToken(0))) return 0;
1117
/* FIXME: do something with reserve size */
1118
return 1;
1119
}
1120
1121
1122
/*******************************************************************
1123
* parse_def_export
1124
*
1125
* Parse an export declaration in a .def file.
1126
*/
1127
static int parse_def_export( char *name, DLLSPEC *spec )
1128
{
1129
int i, args;
1130
const char *token = GetToken(1);
1131
ORDDEF *odp = add_entry_point( spec );
1132
1133
odp->lineno = current_line;
1134
odp->ordinal = -1;
1135
odp->name = name;
1136
args = remove_stdcall_decoration( odp->name );
1137
if (args == -1)
1138
{
1139
odp->type = TYPE_CDECL;
1140
args = 0;
1141
}
1142
else
1143
{
1144
odp->type = TYPE_STDCALL;
1145
args /= get_ptr_size();
1146
if (args >= MAX_ARGUMENTS)
1147
{
1148
error( "Too many arguments in stdcall function '%s'\n", odp->name );
1149
return 0;
1150
}
1151
for (i = 0; i < args; i++) odp->u.func.args[i] = ARG_LONG;
1152
}
1153
odp->u.func.nb_args = args;
1154
1155
/* check for optional internal name */
1156
1157
if (token && !strcmp( token, "=" ))
1158
{
1159
if (!(token = GetToken(0))) goto error;
1160
odp->link_name = xstrdup( token );
1161
remove_stdcall_decoration( odp->link_name );
1162
token = GetToken(1);
1163
}
1164
else
1165
{
1166
odp->link_name = xstrdup( name );
1167
}
1168
1169
/* check for optional ordinal */
1170
1171
if (token && token[0] == '@')
1172
{
1173
int ordinal;
1174
1175
if (!IsNumberString( token+1 ))
1176
{
1177
error( "Expected number after '@', got '%s'\n", token+1 );
1178
goto error;
1179
}
1180
ordinal = atoi( token+1 );
1181
if (!ordinal)
1182
{
1183
error( "Ordinal 0 is not valid\n" );
1184
goto error;
1185
}
1186
if (ordinal >= MAX_ORDINALS)
1187
{
1188
error( "Ordinal number %d too large\n", ordinal );
1189
goto error;
1190
}
1191
odp->ordinal = ordinal;
1192
token = GetToken(1);
1193
}
1194
1195
/* check for other optional keywords */
1196
1197
while (token)
1198
{
1199
if (!strcmp( token, "NONAME" ))
1200
{
1201
if (odp->ordinal == -1)
1202
{
1203
error( "NONAME requires an ordinal\n" );
1204
goto error;
1205
}
1206
odp->export_name = odp->name;
1207
odp->name = NULL;
1208
odp->flags |= FLAG_NONAME;
1209
}
1210
else if (!strcmp( token, "PRIVATE" ))
1211
{
1212
odp->flags |= FLAG_PRIVATE;
1213
}
1214
else if (!strcmp( token, "DATA" ))
1215
{
1216
odp->type = TYPE_EXTERN;
1217
}
1218
else
1219
{
1220
error( "Garbage text '%s' found at end of export declaration\n", token );
1221
goto error;
1222
}
1223
token = GetToken(1);
1224
}
1225
return 1;
1226
1227
error:
1228
spec->entry_points.count--;
1229
free( odp->name );
1230
return 0;
1231
}
1232
1233
1234
/*******************************************************************
1235
* parse_def_file
1236
*
1237
* Parse a .def file.
1238
*/
1239
int parse_def_file( FILE *file, DLLSPEC *spec )
1240
{
1241
const char *token;
1242
int in_exports = 0;
1243
1244
input_file = file;
1245
current_line = 0;
1246
1247
comment_chars = ";";
1248
separator_chars = ",=";
1249
1250
while (get_next_line())
1251
{
1252
if (!(token = GetToken(1))) continue;
1253
1254
if (!strcmp( token, "LIBRARY" ) || !strcmp( token, "NAME" ))
1255
{
1256
if (!parse_def_library( spec )) continue;
1257
goto end_of_line;
1258
}
1259
else if (!strcmp( token, "STACKSIZE" ))
1260
{
1261
if (!parse_def_stack_heap_size( 1, spec )) continue;
1262
goto end_of_line;
1263
}
1264
else if (!strcmp( token, "HEAPSIZE" ))
1265
{
1266
if (!parse_def_stack_heap_size( 0, spec )) continue;
1267
goto end_of_line;
1268
}
1269
else if (!strcmp( token, "EXPORTS" ))
1270
{
1271
in_exports = 1;
1272
if (!(token = GetToken(1))) continue;
1273
}
1274
else if (!strcmp( token, "IMPORTS" ))
1275
{
1276
in_exports = 0;
1277
if (!(token = GetToken(1))) continue;
1278
}
1279
else if (!strcmp( token, "SECTIONS" ))
1280
{
1281
in_exports = 0;
1282
if (!(token = GetToken(1))) continue;
1283
}
1284
1285
if (!in_exports) continue; /* ignore this line */
1286
if (!parse_def_export( xstrdup(token), spec )) continue;
1287
1288
end_of_line:
1289
if ((token = GetToken(1))) error( "Syntax error near '%s'\n", token );
1290
}
1291
1292
current_line = 0; /* no longer parsing the input file */
1293
assign_exports( spec, target.cpu, &spec->exports );
1294
return !nb_errors;
1295
}
1296
1297