parser.c 32 KB

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