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
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/port.h"
39 static char ParseBuffer
[512];
40 static char TokenBuffer
[512];
41 static char *ParseNext
= ParseBuffer
;
42 static FILE *input_file
;
44 static const char *separator_chars
;
45 static const char *comment_chars
;
47 /* valid characters in ordinal names */
48 static const char valid_ordname_chars
[] = "/$:-_@?<>abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
50 static const char * const TypeNames
[TYPE_NBTYPES
] =
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 "extern" /* TYPE_EXTERN */
62 static const char * const FlagNames
[] =
64 "norelay", /* FLAG_NORELAY */
65 "noname", /* FLAG_NONAME */
66 "ret16", /* FLAG_RET16 */
67 "ret64", /* FLAG_RET64 */
68 "register", /* FLAG_REGISTER */
69 "private", /* FLAG_PRIVATE */
70 "ordinal", /* FLAG_ORDINAL */
71 "thiscall", /* FLAG_THISCALL */
72 "fastcall", /* FLAG_FASTCALL */
73 "syscall", /* FLAG_SYSCALL */
74 "import", /* FLAG_IMPORT */
78 static const char * const ArgNames
[ARG_MAXARG
+ 1] =
80 "word", /* ARG_WORD */
81 "s_word", /* ARG_SWORD */
82 "segptr", /* ARG_SEGPTR */
83 "segstr", /* ARG_SEGSTR */
84 "long", /* ARG_LONG */
87 "wstr", /* ARG_WSTR */
88 "int64", /* ARG_INT64 */
89 "int128", /* ARG_INT128 */
90 "float", /* ARG_FLOAT */
91 "double" /* ARG_DOUBLE */
94 static int IsNumberString(const char *s
)
96 while (*s
) if (!isdigit(*s
++)) return 0;
100 static inline int is_token_separator( char ch
)
102 return strchr( separator_chars
, ch
) != NULL
;
105 static inline int is_token_comment( char ch
)
107 return strchr( comment_chars
, ch
) != NULL
;
110 /* get the next line from the input file, or return 0 if at eof */
111 static int get_next_line(void)
113 ParseNext
= ParseBuffer
;
115 return (fgets(ParseBuffer
, sizeof(ParseBuffer
), input_file
) != NULL
);
118 static const char * GetToken( int allow_eol
)
121 char *token
= TokenBuffer
;
125 /* remove initial white space */
127 while (isspace(*p
)) p
++;
129 if (*p
== '\\' && p
[1] == '\n') /* line continuation */
131 if (!get_next_line())
133 if (!allow_eol
) error( "Unexpected end of file\n" );
140 if ((*p
== '\0') || is_token_comment(*p
))
142 if (!allow_eol
) error( "Declaration not terminated properly\n" );
149 if (is_token_separator(*p
))
151 /* a separator is always a complete token */
154 else while (*p
!= '\0' && !is_token_separator(*p
) && !isspace(*p
))
157 if (*p
) *token
++ = *p
++;
165 static ORDDEF
*add_entry_point( DLLSPEC
*spec
)
169 if (spec
->nb_entry_points
== spec
->alloc_entry_points
)
171 spec
->alloc_entry_points
+= 128;
172 spec
->entry_points
= xrealloc( spec
->entry_points
,
173 spec
->alloc_entry_points
* sizeof(*spec
->entry_points
) );
175 ret
= &spec
->entry_points
[spec
->nb_entry_points
++];
176 memset( ret
, 0, sizeof(*ret
) );
180 /*******************************************************************
181 * parse_spec_variable
183 * Parse a variable definition in a .spec file.
185 static int parse_spec_variable( ORDDEF
*odp
, DLLSPEC
*spec
)
188 unsigned int *value_array
;
190 int value_array_size
;
193 if (spec
->type
== SPEC_WIN32
)
195 error( "'variable' not supported in Win32, use 'extern' instead\n" );
199 if (!(token
= GetToken(0))) return 0;
202 error( "Expected '(' got '%s'\n", token
);
207 value_array_size
= 25;
208 value_array
= xmalloc(sizeof(*value_array
) * value_array_size
);
212 if (!(token
= GetToken(0)))
220 value_array
[n_values
++] = strtoul(token
, &endptr
, 0);
221 if (n_values
== value_array_size
)
223 value_array_size
+= 25;
224 value_array
= xrealloc(value_array
,
225 sizeof(*value_array
) * value_array_size
);
228 if (endptr
== NULL
|| *endptr
!= '\0')
230 error( "Expected number value, got '%s'\n", token
);
236 odp
->u
.var
.n_values
= n_values
;
237 odp
->u
.var
.values
= xrealloc(value_array
, sizeof(*value_array
) * n_values
);
242 /*******************************************************************
243 * parse_spec_arguments
245 * Parse the arguments of an entry point.
247 static int parse_spec_arguments( ORDDEF
*odp
, DLLSPEC
*spec
, int optional
)
251 int is_win32
= (spec
->type
== SPEC_WIN32
) || (odp
->flags
& FLAG_EXPORT32
);
253 if (!(token
= GetToken( optional
))) return optional
;
256 error( "Expected '(' got '%s'\n", token
);
260 odp
->u
.func
.nb_args
= 0;
261 for (i
= 0; i
< MAX_ARGUMENTS
; i
++)
263 if (!(token
= GetToken(0))) return 0;
267 for (arg
= 0; arg
<= ARG_MAXARG
; arg
++)
268 if (!strcmp( ArgNames
[arg
], token
)) break;
270 if (arg
> ARG_MAXARG
)
272 error( "Unknown argument type '%s'\n", token
);
275 if (is_win32
) switch (arg
)
281 error( "Argument type '%s' only allowed for Win16\n", token
);
284 odp
->u
.func
.args
[i
] = arg
;
288 error( "Too many arguments\n" );
292 odp
->u
.func
.nb_args
= i
;
293 if (odp
->flags
& FLAG_THISCALL
)
295 if (odp
->type
!= TYPE_STDCALL
)
297 error( "A thiscall function must use the stdcall convention\n" );
300 if (!i
|| odp
->u
.func
.args
[0] != ARG_PTR
)
302 error( "First argument of a thiscall function must be a pointer\n" );
306 if (odp
->flags
& FLAG_FASTCALL
)
308 if (odp
->type
!= TYPE_STDCALL
)
310 error( "A fastcall function must use the stdcall convention\n" );
313 if (!i
|| (odp
->u
.func
.args
[0] != ARG_PTR
&& odp
->u
.func
.args
[0] != ARG_LONG
))
315 error( "First argument of a fastcall function must be a pointer or integer\n" );
318 if (i
> 1 && odp
->u
.func
.args
[1] != ARG_PTR
&& odp
->u
.func
.args
[1] != ARG_LONG
)
320 error( "Second argument of a fastcall function must be a pointer or integer\n" );
324 if (odp
->flags
& FLAG_SYSCALL
)
326 if (odp
->type
!= TYPE_STDCALL
&& odp
->type
!= TYPE_CDECL
)
328 error( "A syscall function must use either the stdcall or the cdecl convention\n" );
336 /*******************************************************************
339 * Parse an exported function definition in a .spec file.
341 static int parse_spec_export( ORDDEF
*odp
, DLLSPEC
*spec
)
344 int is_win32
= (spec
->type
== SPEC_WIN32
) || (odp
->flags
& FLAG_EXPORT32
);
346 if (!is_win32
&& odp
->type
== TYPE_STDCALL
)
348 error( "'stdcall' not supported for Win16\n" );
351 if (is_win32
&& odp
->type
== TYPE_PASCAL
)
353 error( "'pascal' not supported for Win32\n" );
357 if (!parse_spec_arguments( odp
, spec
, 0 )) return 0;
359 if (odp
->type
== TYPE_VARARGS
)
360 odp
->flags
|= FLAG_NORELAY
; /* no relay debug possible for varags entry point */
362 if (target_cpu
!= CPU_x86
)
363 odp
->flags
&= ~(FLAG_THISCALL
| FLAG_FASTCALL
);
365 if (!(token
= GetToken(1)))
367 if (!strcmp( odp
->name
, "@" ))
369 error( "Missing handler name for anonymous function\n" );
372 odp
->link_name
= xstrdup( odp
->name
);
376 odp
->link_name
= xstrdup( token
);
377 if (strchr( odp
->link_name
, '.' ))
381 error( "Forwarded functions not supported for Win16\n" );
384 odp
->flags
|= FLAG_FORWARD
;
391 /*******************************************************************
394 * Parse an 'equate' definition in a .spec file.
396 static int parse_spec_equate( ORDDEF
*odp
, DLLSPEC
*spec
)
402 if (spec
->type
== SPEC_WIN32
)
404 error( "'equate' not supported for Win32\n" );
407 if (!(token
= GetToken(0))) return 0;
408 value
= strtol(token
, &endptr
, 0);
409 if (endptr
== NULL
|| *endptr
!= '\0')
411 error( "Expected number value, got '%s'\n", token
);
414 if (value
< -0x8000 || value
> 0xffff)
416 error( "Value %d for absolute symbol doesn't fit in 16 bits\n", value
);
419 odp
->u
.abs
.value
= value
;
424 /*******************************************************************
427 * Parse a 'stub' definition in a .spec file
429 static int parse_spec_stub( ORDDEF
*odp
, DLLSPEC
*spec
)
431 odp
->u
.func
.nb_args
= -1;
432 odp
->link_name
= xstrdup("");
433 /* don't bother generating stubs for Winelib */
434 if (odp
->flags
& FLAG_CPU_MASK
)
435 odp
->flags
&= FLAG_CPU(CPU_x86
) | FLAG_CPU(CPU_x86_64
) | FLAG_CPU(CPU_ARM
) | FLAG_CPU(CPU_ARM64
);
437 odp
->flags
|= FLAG_CPU(CPU_x86
) | FLAG_CPU(CPU_x86_64
) | FLAG_CPU(CPU_ARM
) | FLAG_CPU(CPU_ARM64
);
439 return parse_spec_arguments( odp
, spec
, 1 );
443 /*******************************************************************
446 * Parse an 'extern' definition in a .spec file.
448 static int parse_spec_extern( ORDDEF
*odp
, DLLSPEC
*spec
)
452 if (spec
->type
== SPEC_WIN16
)
454 error( "'extern' not supported for Win16, use 'variable' instead\n" );
457 if (!(token
= GetToken(1)))
459 if (!strcmp( odp
->name
, "@" ))
461 error( "Missing handler name for anonymous extern\n" );
464 odp
->link_name
= xstrdup( odp
->name
);
468 odp
->link_name
= xstrdup( token
);
469 if (strchr( odp
->link_name
, '.' )) odp
->flags
|= FLAG_FORWARD
;
475 /*******************************************************************
478 * Parse the optional flags for an entry point in a .spec file.
480 static const char *parse_spec_flags( DLLSPEC
*spec
, ORDDEF
*odp
)
482 unsigned int i
, cpu_mask
= 0;
487 if (!(token
= GetToken(0))) break;
488 if (!strncmp( token
, "arch=", 5))
490 char *args
= xstrdup( token
+ 5 );
491 char *cpu_name
= strtok( args
, "," );
494 if (!strcmp( cpu_name
, "win32" ))
496 if (spec
->type
== SPEC_WIN32
)
497 odp
->flags
|= FLAG_CPU_WIN32
;
499 odp
->flags
|= FLAG_EXPORT32
;
501 else if (!strcmp( cpu_name
, "win64" ))
502 odp
->flags
|= FLAG_CPU_WIN64
;
505 int cpu
= get_cpu_from_name( cpu_name
+ (cpu_name
[0] == '!') );
508 error( "Unknown architecture '%s'\n", cpu_name
);
511 if (cpu_name
[0] == '!') cpu_mask
|= FLAG_CPU( cpu
);
512 else odp
->flags
|= FLAG_CPU( cpu
);
514 cpu_name
= strtok( NULL
, "," );
518 else if (!strcmp( token
, "i386" )) /* backwards compatibility */
520 odp
->flags
|= FLAG_CPU(CPU_x86
);
524 for (i
= 0; FlagNames
[i
]; i
++)
525 if (!strcmp( FlagNames
[i
], token
)) break;
528 error( "Unknown flag '%s'\n", token
);
535 if (spec
->type
== SPEC_WIN32
)
536 error( "Flag '%s' is not supported in Win32\n", FlagNames
[i
] );
541 if (spec
->type
== SPEC_WIN16
)
542 error( "Flag '%s' is not supported in Win16\n", FlagNames
[i
] );
545 odp
->flags
|= 1 << i
;
548 } while (token
&& *token
== '-');
550 if (cpu_mask
) odp
->flags
|= FLAG_CPU_MASK
& ~cpu_mask
;
555 /*******************************************************************
558 * Parse an ordinal definition in a .spec file.
560 static int parse_spec_ordinal( int ordinal
, DLLSPEC
*spec
)
564 ORDDEF
*odp
= add_entry_point( spec
);
566 if (!(token
= GetToken(0))) goto error
;
568 for (odp
->type
= 0; odp
->type
< TYPE_NBTYPES
; odp
->type
++)
569 if (TypeNames
[odp
->type
] && !strcmp( token
, TypeNames
[odp
->type
] ))
572 if (odp
->type
>= TYPE_NBTYPES
)
574 if (!strcmp( token
, "thiscall" )) /* for backwards compatibility */
576 odp
->type
= TYPE_STDCALL
;
577 odp
->flags
|= FLAG_THISCALL
;
581 error( "Expected type after ordinal, found '%s' instead\n", token
);
586 if (!(token
= GetToken(0))) goto error
;
587 if (*token
== '-' && !(token
= parse_spec_flags( spec
, odp
))) goto error
;
589 if (ordinal
== -1 && spec
->type
!= SPEC_WIN32
&& !(odp
->flags
& FLAG_EXPORT32
))
591 error( "'@' ordinals not supported for Win16\n" );
595 odp
->name
= xstrdup( token
);
596 odp
->lineno
= current_line
;
597 odp
->ordinal
= ordinal
;
599 len
= strspn( odp
->name
, valid_ordname_chars
);
600 if (len
< strlen( odp
->name
))
602 error( "Character '%c' is not allowed in exported name '%s'\n", odp
->name
[len
], odp
->name
);
609 if (!parse_spec_variable( odp
, spec
)) goto error
;
615 if (!parse_spec_export( odp
, spec
)) goto error
;
618 if (!parse_spec_equate( odp
, spec
)) goto error
;
621 if (!parse_spec_stub( odp
, spec
)) goto error
;
624 if (!parse_spec_extern( odp
, spec
)) goto error
;
630 if ((odp
->flags
& FLAG_CPU_MASK
) && !(odp
->flags
& FLAG_CPU(target_cpu
)))
632 /* ignore this entry point */
633 spec
->nb_entry_points
--;
641 error( "Ordinal 0 is not valid\n" );
644 if (ordinal
>= MAX_ORDINALS
)
646 error( "Ordinal number %d too large\n", ordinal
);
649 if (ordinal
> spec
->limit
) spec
->limit
= ordinal
;
650 if (ordinal
< spec
->base
) spec
->base
= ordinal
;
651 odp
->ordinal
= ordinal
;
654 if (odp
->type
== TYPE_STDCALL
&& !(odp
->flags
& FLAG_PRIVATE
))
656 if (!strcmp( odp
->name
, "DllRegisterServer" ) ||
657 !strcmp( odp
->name
, "DllUnregisterServer" ) ||
658 !strcmp( odp
->name
, "DllMain" ) ||
659 !strcmp( odp
->name
, "DllGetClassObject" ) ||
660 !strcmp( odp
->name
, "DllGetVersion" ) ||
661 !strcmp( odp
->name
, "DllInstall" ) ||
662 !strcmp( odp
->name
, "DllCanUnloadNow" ))
664 warning( "Function %s should be marked private\n", odp
->name
);
665 if (strcmp( odp
->name
, odp
->link_name
))
666 warning( "Function %s should not use a different internal name (%s)\n",
667 odp
->name
, odp
->link_name
);
671 if (!strcmp( odp
->name
, "@" ) || odp
->flags
& (FLAG_NONAME
| FLAG_ORDINAL
))
675 if (!strcmp( odp
->name
, "@" ))
676 error( "Nameless function needs an explicit ordinal number\n" );
678 error( "Function imported by ordinal needs an explicit ordinal number\n" );
681 if (spec
->type
!= SPEC_WIN32
)
683 error( "Nameless functions not supported for Win16\n" );
686 if (!strcmp( odp
->name
, "@" ))
691 else if (!(odp
->flags
& FLAG_ORDINAL
)) /* -ordinal only affects the import library */
693 odp
->export_name
= odp
->name
;
700 spec
->nb_entry_points
--;
706 static int name_compare( const void *ptr1
, const void *ptr2
)
708 const ORDDEF
*odp1
= *(const ORDDEF
* const *)ptr1
;
709 const ORDDEF
*odp2
= *(const ORDDEF
* const *)ptr2
;
710 const char *name1
= odp1
->name
? odp1
->name
: odp1
->export_name
;
711 const char *name2
= odp2
->name
? odp2
->name
: odp2
->export_name
;
712 return strcmp( name1
, name2
);
715 /*******************************************************************
718 * Build the name array and catch duplicates.
720 static void assign_names( DLLSPEC
*spec
)
722 int i
, j
, nb_exp_names
= 0;
726 for (i
= 0; i
< spec
->nb_entry_points
; i
++)
727 if (spec
->entry_points
[i
].name
) spec
->nb_names
++;
728 else if (spec
->entry_points
[i
].export_name
) nb_exp_names
++;
730 if (!spec
->nb_names
&& !nb_exp_names
) return;
732 /* check for duplicates */
734 all_names
= xmalloc( (spec
->nb_names
+ nb_exp_names
) * sizeof(all_names
[0]) );
735 for (i
= j
= 0; i
< spec
->nb_entry_points
; i
++)
736 if (spec
->entry_points
[i
].name
|| spec
->entry_points
[i
].export_name
)
737 all_names
[j
++] = &spec
->entry_points
[i
];
739 qsort( all_names
, j
, sizeof(all_names
[0]), name_compare
);
741 for (i
= 0; i
< j
- 1; i
++)
743 const char *name1
= all_names
[i
]->name
? all_names
[i
]->name
: all_names
[i
]->export_name
;
744 const char *name2
= all_names
[i
+1]->name
? all_names
[i
+1]->name
: all_names
[i
+1]->export_name
;
745 if (!strcmp( name1
, name2
) &&
746 !((all_names
[i
]->flags
^ all_names
[i
+1]->flags
) & FLAG_EXPORT32
))
748 current_line
= max( all_names
[i
]->lineno
, all_names
[i
+1]->lineno
);
749 error( "'%s' redefined\n%s:%d: First defined here\n",
750 name1
, input_file_name
,
751 min( all_names
[i
]->lineno
, all_names
[i
+1]->lineno
) );
758 spec
->names
= xmalloc( spec
->nb_names
* sizeof(spec
->names
[0]) );
759 for (i
= j
= 0; i
< spec
->nb_entry_points
; i
++)
760 if (spec
->entry_points
[i
].name
) spec
->names
[j
++] = &spec
->entry_points
[i
];
762 /* sort the list of names */
763 qsort( spec
->names
, spec
->nb_names
, sizeof(spec
->names
[0]), name_compare
);
764 for (i
= 0; i
< spec
->nb_names
; i
++) spec
->names
[i
]->hint
= i
;
768 /*******************************************************************
771 * Build the ordinal array.
773 static void assign_ordinals( DLLSPEC
*spec
)
775 int i
, count
, ordinal
;
777 /* start assigning from base, or from 1 if no ordinal defined yet */
779 spec
->base
= MAX_ORDINALS
;
781 for (i
= 0; i
< spec
->nb_entry_points
; i
++)
783 ordinal
= spec
->entry_points
[i
].ordinal
;
784 if (ordinal
== -1) continue;
785 if (ordinal
> spec
->limit
) spec
->limit
= ordinal
;
786 if (ordinal
< spec
->base
) spec
->base
= ordinal
;
788 if (spec
->base
== MAX_ORDINALS
) spec
->base
= 1;
789 if (spec
->limit
< spec
->base
) spec
->limit
= spec
->base
;
791 count
= max( spec
->limit
+ 1, spec
->base
+ spec
->nb_entry_points
);
792 spec
->ordinals
= xmalloc( count
* sizeof(spec
->ordinals
[0]) );
793 memset( spec
->ordinals
, 0, count
* sizeof(spec
->ordinals
[0]) );
795 /* fill in all explicitly specified ordinals */
796 for (i
= 0; i
< spec
->nb_entry_points
; i
++)
798 ordinal
= spec
->entry_points
[i
].ordinal
;
799 if (ordinal
== -1) continue;
800 if (spec
->ordinals
[ordinal
])
802 current_line
= max( spec
->entry_points
[i
].lineno
, spec
->ordinals
[ordinal
]->lineno
);
803 error( "ordinal %d redefined\n%s:%d: First defined here\n",
804 ordinal
, input_file_name
,
805 min( spec
->entry_points
[i
].lineno
, spec
->ordinals
[ordinal
]->lineno
) );
807 else spec
->ordinals
[ordinal
] = &spec
->entry_points
[i
];
810 /* now assign ordinals to the rest */
811 for (i
= 0, ordinal
= spec
->base
; i
< spec
->nb_entry_points
; i
++)
813 if (spec
->entry_points
[i
].ordinal
!= -1) continue;
814 while (spec
->ordinals
[ordinal
]) ordinal
++;
815 if (ordinal
>= MAX_ORDINALS
)
817 current_line
= spec
->entry_points
[i
].lineno
;
818 fatal_error( "Too many functions defined (max %d)\n", MAX_ORDINALS
);
820 spec
->entry_points
[i
].ordinal
= ordinal
;
821 spec
->ordinals
[ordinal
] = &spec
->entry_points
[i
];
823 if (ordinal
> spec
->limit
) spec
->limit
= ordinal
;
827 /*******************************************************************
830 * Add the necessary exports to the 32-bit counterpart of a 16-bit module.
832 void add_16bit_exports( DLLSPEC
*spec32
, DLLSPEC
*spec16
)
837 spec32
->file_name
= xstrdup( spec16
->file_name
);
838 spec32
->characteristics
= IMAGE_FILE_DLL
;
839 spec32
->init_func
= xstrdup( "DllMain" );
841 /* add an export for the NE module */
843 odp
= add_entry_point( spec32
);
844 odp
->type
= TYPE_EXTERN
;
845 odp
->flags
= FLAG_PRIVATE
;
846 odp
->name
= xstrdup( "__wine_spec_dos_header" );
849 odp
->link_name
= xstrdup( ".L__wine_spec_dos_header" );
851 if (spec16
->main_module
)
853 odp
= add_entry_point( spec32
);
854 odp
->type
= TYPE_EXTERN
;
855 odp
->flags
= FLAG_PRIVATE
;
856 odp
->name
= xstrdup( "__wine_spec_main_module" );
859 odp
->link_name
= xstrdup( ".L__wine_spec_main_module" );
862 /* add the explicit win32 exports */
864 for (i
= 1; i
<= spec16
->limit
; i
++)
866 ORDDEF
*odp16
= spec16
->ordinals
[i
];
868 if (!odp16
|| !odp16
->name
) continue;
869 if (!(odp16
->flags
& FLAG_EXPORT32
)) continue;
871 odp
= add_entry_point( spec32
);
872 odp
->flags
= odp16
->flags
& ~FLAG_EXPORT32
;
873 odp
->type
= odp16
->type
;
874 odp
->name
= xstrdup( odp16
->name
);
875 odp
->lineno
= odp16
->lineno
;
877 odp
->link_name
= xstrdup( odp16
->link_name
);
878 odp
->u
.func
.nb_args
= odp16
->u
.func
.nb_args
;
879 if (odp
->u
.func
.nb_args
> 0) memcpy( odp
->u
.func
.args
, odp16
->u
.func
.args
,
880 odp
->u
.func
.nb_args
* sizeof(odp
->u
.func
.args
[0]) );
883 assign_names( spec32
);
884 assign_ordinals( spec32
);
888 /*******************************************************************
891 * Parse a .spec file.
893 int parse_spec_file( FILE *file
, DLLSPEC
*spec
)
900 comment_chars
= "#;";
901 separator_chars
= "()-";
903 while (get_next_line())
905 if (!(token
= GetToken(1))) continue;
906 if (strcmp(token
, "@") == 0)
908 if (!parse_spec_ordinal( -1, spec
)) continue;
910 else if (IsNumberString(token
))
912 if (!parse_spec_ordinal( atoi(token
), spec
)) continue;
916 error( "Expected ordinal declaration, got '%s'\n", token
);
919 if ((token
= GetToken(1))) error( "Syntax error near '%s'\n", token
);
922 current_line
= 0; /* no longer parsing the input file */
923 assign_names( spec
);
924 assign_ordinals( spec
);
929 /*******************************************************************
932 * Parse a LIBRARY declaration in a .def file.
934 static int parse_def_library( DLLSPEC
*spec
)
936 const char *token
= GetToken(1);
938 if (!token
) return 1;
939 if (strcmp( token
, "BASE" ))
941 free( spec
->file_name
);
942 spec
->file_name
= xstrdup( token
);
943 if (!(token
= GetToken(1))) return 1;
945 if (strcmp( token
, "BASE" ))
947 error( "Expected library name or BASE= declaration, got '%s'\n", token
);
950 if (!(token
= GetToken(0))) return 0;
951 if (strcmp( token
, "=" ))
953 error( "Expected '=' after BASE, got '%s'\n", token
);
956 if (!(token
= GetToken(0))) return 0;
957 /* FIXME: do something with base address */
963 /*******************************************************************
964 * parse_def_stack_heap_size
966 * Parse a STACKSIZE or HEAPSIZE declaration in a .def file.
968 static int parse_def_stack_heap_size( int is_stack
, DLLSPEC
*spec
)
970 const char *token
= GetToken(0);
974 if (!token
) return 0;
975 size
= strtoul( token
, &end
, 0 );
978 error( "Invalid number '%s'\n", token
);
981 if (is_stack
) spec
->stack_size
= size
/ 1024;
982 else spec
->heap_size
= size
/ 1024;
983 if (!(token
= GetToken(1))) return 1;
984 if (strcmp( token
, "," ))
986 error( "Expected ',' after size, got '%s'\n", token
);
989 if (!(token
= GetToken(0))) return 0;
990 /* FIXME: do something with reserve size */
995 /*******************************************************************
998 * Parse an export declaration in a .def file.
1000 static int parse_def_export( char *name
, DLLSPEC
*spec
)
1003 const char *token
= GetToken(1);
1004 ORDDEF
*odp
= add_entry_point( spec
);
1006 odp
->lineno
= current_line
;
1009 args
= remove_stdcall_decoration( odp
->name
);
1012 odp
->type
= TYPE_CDECL
;
1017 odp
->type
= TYPE_STDCALL
;
1018 args
/= get_ptr_size();
1019 if (args
>= MAX_ARGUMENTS
)
1021 error( "Too many arguments in stdcall function '%s'\n", odp
->name
);
1024 for (i
= 0; i
< args
; i
++) odp
->u
.func
.args
[i
] = ARG_LONG
;
1026 odp
->u
.func
.nb_args
= args
;
1028 /* check for optional internal name */
1030 if (token
&& !strcmp( token
, "=" ))
1032 if (!(token
= GetToken(0))) goto error
;
1033 odp
->link_name
= xstrdup( token
);
1034 remove_stdcall_decoration( odp
->link_name
);
1035 token
= GetToken(1);
1039 odp
->link_name
= xstrdup( name
);
1042 /* check for optional ordinal */
1044 if (token
&& token
[0] == '@')
1048 if (!IsNumberString( token
+1 ))
1050 error( "Expected number after '@', got '%s'\n", token
+1 );
1053 ordinal
= atoi( token
+1 );
1056 error( "Ordinal 0 is not valid\n" );
1059 if (ordinal
>= MAX_ORDINALS
)
1061 error( "Ordinal number %d too large\n", ordinal
);
1064 odp
->ordinal
= ordinal
;
1065 token
= GetToken(1);
1068 /* check for other optional keywords */
1072 if (!strcmp( token
, "NONAME" ))
1074 if (odp
->ordinal
== -1)
1076 error( "NONAME requires an ordinal\n" );
1079 odp
->export_name
= odp
->name
;
1081 odp
->flags
|= FLAG_NONAME
;
1083 else if (!strcmp( token
, "PRIVATE" ))
1085 odp
->flags
|= FLAG_PRIVATE
;
1087 else if (!strcmp( token
, "DATA" ))
1089 odp
->type
= TYPE_EXTERN
;
1093 error( "Garbage text '%s' found at end of export declaration\n", token
);
1096 token
= GetToken(1);
1101 spec
->nb_entry_points
--;
1107 /*******************************************************************
1110 * Parse a .def file.
1112 int parse_def_file( FILE *file
, DLLSPEC
*spec
)
1120 comment_chars
= ";";
1121 separator_chars
= ",=";
1123 while (get_next_line())
1125 if (!(token
= GetToken(1))) continue;
1127 if (!strcmp( token
, "LIBRARY" ) || !strcmp( token
, "NAME" ))
1129 if (!parse_def_library( spec
)) continue;
1132 else if (!strcmp( token
, "STACKSIZE" ))
1134 if (!parse_def_stack_heap_size( 1, spec
)) continue;
1137 else if (!strcmp( token
, "HEAPSIZE" ))
1139 if (!parse_def_stack_heap_size( 0, spec
)) continue;
1142 else if (!strcmp( token
, "EXPORTS" ))
1145 if (!(token
= GetToken(1))) continue;
1147 else if (!strcmp( token
, "IMPORTS" ))
1150 if (!(token
= GetToken(1))) continue;
1152 else if (!strcmp( token
, "SECTIONS" ))
1155 if (!(token
= GetToken(1))) continue;
1158 if (!in_exports
) continue; /* ignore this line */
1159 if (!parse_def_export( xstrdup(token
), spec
)) continue;
1162 if ((token
= GetToken(1))) error( "Syntax error near '%s'\n", token
);
1165 current_line
= 0; /* no longer parsing the input file */
1166 assign_names( spec
);
1167 assign_ordinals( spec
);