parser.c 32 KB

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