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