parser.c 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163
  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 <assert.h>
  26. #include <ctype.h>
  27. #include <stdarg.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include "build.h"
  32. int current_line = 0;
  33. static char ParseBuffer[512];
  34. static char TokenBuffer[512];
  35. static char *ParseNext = ParseBuffer;
  36. static FILE *input_file;
  37. static const char *separator_chars;
  38. static const char *comment_chars;
  39. /* valid characters in ordinal names */
  40. static const char valid_ordname_chars[] = "/$:-_@?<>abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  41. static const char * const TypeNames[TYPE_NBTYPES] =
  42. {
  43. "variable", /* TYPE_VARIABLE */
  44. "pascal", /* TYPE_PASCAL */
  45. "equate", /* TYPE_ABS */
  46. "stub", /* TYPE_STUB */
  47. "stdcall", /* TYPE_STDCALL */
  48. "cdecl", /* TYPE_CDECL */
  49. "varargs", /* TYPE_VARARGS */
  50. "extern" /* TYPE_EXTERN */
  51. };
  52. static const char * const FlagNames[] =
  53. {
  54. "norelay", /* FLAG_NORELAY */
  55. "noname", /* FLAG_NONAME */
  56. "ret16", /* FLAG_RET16 */
  57. "ret64", /* FLAG_RET64 */
  58. "register", /* FLAG_REGISTER */
  59. "private", /* FLAG_PRIVATE */
  60. "ordinal", /* FLAG_ORDINAL */
  61. "thiscall", /* FLAG_THISCALL */
  62. "fastcall", /* FLAG_FASTCALL */
  63. "syscall", /* FLAG_SYSCALL */
  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. if (odp->flags & FLAG_SYSCALL)
  287. {
  288. if (odp->type != TYPE_STDCALL && odp->type != TYPE_CDECL)
  289. {
  290. error( "A syscall function must use either the stdcall or the cdecl convention\n" );
  291. return 0;
  292. }
  293. }
  294. return 1;
  295. }
  296. /*******************************************************************
  297. * parse_spec_export
  298. *
  299. * Parse an exported function definition in a .spec file.
  300. */
  301. static int parse_spec_export( ORDDEF *odp, DLLSPEC *spec )
  302. {
  303. const char *token;
  304. int is_win32 = (spec->type == SPEC_WIN32) || (odp->flags & FLAG_EXPORT32);
  305. if (!is_win32 && odp->type == TYPE_STDCALL)
  306. {
  307. error( "'stdcall' not supported for Win16\n" );
  308. return 0;
  309. }
  310. if (is_win32 && odp->type == TYPE_PASCAL)
  311. {
  312. error( "'pascal' not supported for Win32\n" );
  313. return 0;
  314. }
  315. if (!parse_spec_arguments( odp, spec, 0 )) return 0;
  316. if (odp->type == TYPE_VARARGS)
  317. odp->flags |= FLAG_NORELAY; /* no relay debug possible for varags entry point */
  318. if (target.cpu != CPU_i386)
  319. odp->flags &= ~(FLAG_THISCALL | FLAG_FASTCALL);
  320. if (!(token = GetToken(1)))
  321. {
  322. if (!strcmp( odp->name, "@" ))
  323. {
  324. error( "Missing handler name for anonymous function\n" );
  325. return 0;
  326. }
  327. odp->link_name = xstrdup( odp->name );
  328. }
  329. else
  330. {
  331. odp->link_name = xstrdup( token );
  332. if (strchr( odp->link_name, '.' ))
  333. {
  334. if (!is_win32)
  335. {
  336. error( "Forwarded functions not supported for Win16\n" );
  337. return 0;
  338. }
  339. odp->flags |= FLAG_FORWARD;
  340. }
  341. }
  342. return 1;
  343. }
  344. /*******************************************************************
  345. * parse_spec_equate
  346. *
  347. * Parse an 'equate' definition in a .spec file.
  348. */
  349. static int parse_spec_equate( ORDDEF *odp, DLLSPEC *spec )
  350. {
  351. char *endptr;
  352. int value;
  353. const char *token;
  354. if (spec->type == SPEC_WIN32)
  355. {
  356. error( "'equate' not supported for Win32\n" );
  357. return 0;
  358. }
  359. if (!(token = GetToken(0))) return 0;
  360. value = strtol(token, &endptr, 0);
  361. if (endptr == NULL || *endptr != '\0')
  362. {
  363. error( "Expected number value, got '%s'\n", token );
  364. return 0;
  365. }
  366. if (value < -0x8000 || value > 0xffff)
  367. {
  368. error( "Value %d for absolute symbol doesn't fit in 16 bits\n", value );
  369. value = 0;
  370. }
  371. odp->u.abs.value = value;
  372. return 1;
  373. }
  374. /*******************************************************************
  375. * parse_spec_stub
  376. *
  377. * Parse a 'stub' definition in a .spec file
  378. */
  379. static int parse_spec_stub( ORDDEF *odp, DLLSPEC *spec )
  380. {
  381. odp->u.func.nb_args = -1;
  382. odp->link_name = xstrdup("");
  383. return parse_spec_arguments( odp, spec, 1 );
  384. }
  385. /*******************************************************************
  386. * parse_spec_extern
  387. *
  388. * Parse an 'extern' definition in a .spec file.
  389. */
  390. static int parse_spec_extern( ORDDEF *odp, DLLSPEC *spec )
  391. {
  392. const char *token;
  393. if (spec->type == SPEC_WIN16)
  394. {
  395. error( "'extern' not supported for Win16, use 'variable' instead\n" );
  396. return 0;
  397. }
  398. if (!(token = GetToken(1)))
  399. {
  400. if (!strcmp( odp->name, "@" ))
  401. {
  402. error( "Missing handler name for anonymous extern\n" );
  403. return 0;
  404. }
  405. odp->link_name = xstrdup( odp->name );
  406. }
  407. else
  408. {
  409. odp->link_name = xstrdup( token );
  410. if (strchr( odp->link_name, '.' )) odp->flags |= FLAG_FORWARD;
  411. }
  412. return 1;
  413. }
  414. /*******************************************************************
  415. * parse_spec_flags
  416. *
  417. * Parse the optional flags for an entry point in a .spec file.
  418. */
  419. static const char *parse_spec_flags( DLLSPEC *spec, ORDDEF *odp )
  420. {
  421. unsigned int i, cpu_mask = 0;
  422. const char *token;
  423. do
  424. {
  425. if (!(token = GetToken(0))) break;
  426. if (!strncmp( token, "arch=", 5))
  427. {
  428. char *args = xstrdup( token + 5 );
  429. char *cpu_name = strtok( args, "," );
  430. while (cpu_name)
  431. {
  432. if (!strcmp( cpu_name, "win32" ))
  433. {
  434. if (spec->type == SPEC_WIN32)
  435. odp->flags |= FLAG_CPU_WIN32;
  436. else
  437. odp->flags |= FLAG_EXPORT32;
  438. }
  439. else if (!strcmp( cpu_name, "win64" ))
  440. odp->flags |= FLAG_CPU_WIN64;
  441. else
  442. {
  443. int cpu = get_cpu_from_name( cpu_name + (cpu_name[0] == '!') );
  444. if (cpu == -1)
  445. {
  446. error( "Unknown architecture '%s'\n", cpu_name );
  447. return NULL;
  448. }
  449. if (cpu_name[0] == '!') cpu_mask |= FLAG_CPU( cpu );
  450. else odp->flags |= FLAG_CPU( cpu );
  451. }
  452. cpu_name = strtok( NULL, "," );
  453. }
  454. free( args );
  455. }
  456. else if (!strcmp( token, "i386" )) /* backwards compatibility */
  457. {
  458. odp->flags |= FLAG_CPU(CPU_i386);
  459. }
  460. else
  461. {
  462. for (i = 0; FlagNames[i]; i++)
  463. if (!strcmp( FlagNames[i], token )) break;
  464. if (!FlagNames[i])
  465. {
  466. error( "Unknown flag '%s'\n", token );
  467. return NULL;
  468. }
  469. switch (1 << i)
  470. {
  471. case FLAG_RET16:
  472. case FLAG_REGISTER:
  473. if (spec->type == SPEC_WIN32)
  474. error( "Flag '%s' is not supported in Win32\n", FlagNames[i] );
  475. break;
  476. case FLAG_RET64:
  477. case FLAG_THISCALL:
  478. case FLAG_FASTCALL:
  479. if (spec->type == SPEC_WIN16)
  480. error( "Flag '%s' is not supported in Win16\n", FlagNames[i] );
  481. break;
  482. }
  483. odp->flags |= 1 << i;
  484. }
  485. token = GetToken(0);
  486. } while (token && *token == '-');
  487. if (cpu_mask) odp->flags |= FLAG_CPU_MASK & ~cpu_mask;
  488. return token;
  489. }
  490. /*******************************************************************
  491. * parse_spec_ordinal
  492. *
  493. * Parse an ordinal definition in a .spec file.
  494. */
  495. static int parse_spec_ordinal( int ordinal, DLLSPEC *spec )
  496. {
  497. const char *token;
  498. size_t len;
  499. ORDDEF *odp = add_entry_point( spec );
  500. if (!(token = GetToken(0))) goto error;
  501. for (odp->type = 0; odp->type < TYPE_NBTYPES; odp->type++)
  502. if (TypeNames[odp->type] && !strcmp( token, TypeNames[odp->type] ))
  503. break;
  504. if (odp->type >= TYPE_NBTYPES)
  505. {
  506. if (!strcmp( token, "thiscall" )) /* for backwards compatibility */
  507. {
  508. odp->type = TYPE_STDCALL;
  509. odp->flags |= FLAG_THISCALL;
  510. }
  511. else
  512. {
  513. error( "Expected type after ordinal, found '%s' instead\n", token );
  514. goto error;
  515. }
  516. }
  517. if (!(token = GetToken(0))) goto error;
  518. if (*token == '-' && !(token = parse_spec_flags( spec, odp ))) goto error;
  519. if (ordinal == -1 && spec->type != SPEC_WIN32 && !(odp->flags & FLAG_EXPORT32))
  520. {
  521. error( "'@' ordinals not supported for Win16\n" );
  522. goto error;
  523. }
  524. odp->name = xstrdup( token );
  525. odp->lineno = current_line;
  526. odp->ordinal = ordinal;
  527. len = strspn( odp->name, valid_ordname_chars );
  528. if (len < strlen( odp->name ))
  529. {
  530. error( "Character '%c' is not allowed in exported name '%s'\n", odp->name[len], odp->name );
  531. goto error;
  532. }
  533. switch(odp->type)
  534. {
  535. case TYPE_VARIABLE:
  536. if (!parse_spec_variable( odp, spec )) goto error;
  537. break;
  538. case TYPE_PASCAL:
  539. case TYPE_STDCALL:
  540. case TYPE_VARARGS:
  541. case TYPE_CDECL:
  542. if (!parse_spec_export( odp, spec )) goto error;
  543. break;
  544. case TYPE_ABS:
  545. if (!parse_spec_equate( odp, spec )) goto error;
  546. break;
  547. case TYPE_STUB:
  548. if (!parse_spec_stub( odp, spec )) goto error;
  549. break;
  550. case TYPE_EXTERN:
  551. if (!parse_spec_extern( odp, spec )) goto error;
  552. break;
  553. default:
  554. assert( 0 );
  555. }
  556. if ((odp->flags & FLAG_CPU_MASK) && !(odp->flags & FLAG_CPU(target.cpu)))
  557. {
  558. /* ignore this entry point */
  559. spec->nb_entry_points--;
  560. return 1;
  561. }
  562. if (ordinal != -1)
  563. {
  564. if (!ordinal)
  565. {
  566. error( "Ordinal 0 is not valid\n" );
  567. goto error;
  568. }
  569. if (ordinal >= MAX_ORDINALS)
  570. {
  571. error( "Ordinal number %d too large\n", ordinal );
  572. goto error;
  573. }
  574. if (ordinal > spec->limit) spec->limit = ordinal;
  575. if (ordinal < spec->base) spec->base = ordinal;
  576. odp->ordinal = ordinal;
  577. }
  578. if (odp->type == TYPE_STDCALL && !(odp->flags & FLAG_PRIVATE))
  579. {
  580. if (!strcmp( odp->name, "DllRegisterServer" ) ||
  581. !strcmp( odp->name, "DllUnregisterServer" ) ||
  582. !strcmp( odp->name, "DllMain" ) ||
  583. !strcmp( odp->name, "DllGetClassObject" ) ||
  584. !strcmp( odp->name, "DllGetVersion" ) ||
  585. !strcmp( odp->name, "DllInstall" ) ||
  586. !strcmp( odp->name, "DllCanUnloadNow" ))
  587. {
  588. warning( "Function %s should be marked private\n", odp->name );
  589. if (strcmp( odp->name, odp->link_name ))
  590. warning( "Function %s should not use a different internal name (%s)\n",
  591. odp->name, odp->link_name );
  592. }
  593. }
  594. if (!strcmp( odp->name, "@" ) || odp->flags & (FLAG_NONAME | FLAG_ORDINAL))
  595. {
  596. if (ordinal == -1)
  597. {
  598. if (!strcmp( odp->name, "@" ))
  599. error( "Nameless function needs an explicit ordinal number\n" );
  600. else
  601. error( "Function imported by ordinal needs an explicit ordinal number\n" );
  602. goto error;
  603. }
  604. if (spec->type != SPEC_WIN32)
  605. {
  606. error( "Nameless functions not supported for Win16\n" );
  607. goto error;
  608. }
  609. if (!strcmp( odp->name, "@" ))
  610. {
  611. free( odp->name );
  612. odp->name = NULL;
  613. }
  614. else if (!(odp->flags & FLAG_ORDINAL)) /* -ordinal only affects the import library */
  615. {
  616. odp->export_name = odp->name;
  617. odp->name = NULL;
  618. }
  619. }
  620. return 1;
  621. error:
  622. spec->nb_entry_points--;
  623. free( odp->name );
  624. return 0;
  625. }
  626. static int name_compare( const void *ptr1, const void *ptr2 )
  627. {
  628. const ORDDEF *odp1 = *(const ORDDEF * const *)ptr1;
  629. const ORDDEF *odp2 = *(const ORDDEF * const *)ptr2;
  630. const char *name1 = odp1->name ? odp1->name : odp1->export_name;
  631. const char *name2 = odp2->name ? odp2->name : odp2->export_name;
  632. return strcmp( name1, name2 );
  633. }
  634. /*******************************************************************
  635. * assign_names
  636. *
  637. * Build the name array and catch duplicates.
  638. */
  639. static void assign_names( DLLSPEC *spec )
  640. {
  641. int i, j, nb_exp_names = 0;
  642. ORDDEF **all_names;
  643. spec->nb_names = 0;
  644. for (i = 0; i < spec->nb_entry_points; i++)
  645. if (spec->entry_points[i].name) spec->nb_names++;
  646. else if (spec->entry_points[i].export_name) nb_exp_names++;
  647. if (!spec->nb_names && !nb_exp_names) return;
  648. /* check for duplicates */
  649. all_names = xmalloc( (spec->nb_names + nb_exp_names) * sizeof(all_names[0]) );
  650. for (i = j = 0; i < spec->nb_entry_points; i++)
  651. if (spec->entry_points[i].name || spec->entry_points[i].export_name)
  652. all_names[j++] = &spec->entry_points[i];
  653. qsort( all_names, j, sizeof(all_names[0]), name_compare );
  654. for (i = 0; i < j - 1; i++)
  655. {
  656. const char *name1 = all_names[i]->name ? all_names[i]->name : all_names[i]->export_name;
  657. const char *name2 = all_names[i+1]->name ? all_names[i+1]->name : all_names[i+1]->export_name;
  658. if (!strcmp( name1, name2 ) &&
  659. !((all_names[i]->flags ^ all_names[i+1]->flags) & FLAG_EXPORT32))
  660. {
  661. current_line = max( all_names[i]->lineno, all_names[i+1]->lineno );
  662. error( "'%s' redefined\n%s:%d: First defined here\n",
  663. name1, input_file_name,
  664. min( all_names[i]->lineno, all_names[i+1]->lineno ) );
  665. }
  666. }
  667. free( all_names );
  668. if (spec->nb_names)
  669. {
  670. spec->names = xmalloc( spec->nb_names * sizeof(spec->names[0]) );
  671. for (i = j = 0; i < spec->nb_entry_points; i++)
  672. if (spec->entry_points[i].name) spec->names[j++] = &spec->entry_points[i];
  673. /* sort the list of names */
  674. qsort( spec->names, spec->nb_names, sizeof(spec->names[0]), name_compare );
  675. for (i = 0; i < spec->nb_names; i++) spec->names[i]->hint = i;
  676. }
  677. }
  678. /*******************************************************************
  679. * assign_ordinals
  680. *
  681. * Build the ordinal array.
  682. */
  683. static void assign_ordinals( DLLSPEC *spec )
  684. {
  685. int i, count, ordinal;
  686. /* start assigning from base, or from 1 if no ordinal defined yet */
  687. spec->base = MAX_ORDINALS;
  688. spec->limit = 0;
  689. for (i = 0; i < spec->nb_entry_points; i++)
  690. {
  691. ordinal = spec->entry_points[i].ordinal;
  692. if (ordinal == -1) continue;
  693. if (ordinal > spec->limit) spec->limit = ordinal;
  694. if (ordinal < spec->base) spec->base = ordinal;
  695. }
  696. if (spec->base == MAX_ORDINALS) spec->base = 1;
  697. if (spec->limit < spec->base) spec->limit = spec->base;
  698. count = max( spec->limit + 1, spec->base + spec->nb_entry_points );
  699. spec->ordinals = xmalloc( count * sizeof(spec->ordinals[0]) );
  700. memset( spec->ordinals, 0, count * sizeof(spec->ordinals[0]) );
  701. /* fill in all explicitly specified ordinals */
  702. for (i = 0; i < spec->nb_entry_points; i++)
  703. {
  704. ordinal = spec->entry_points[i].ordinal;
  705. if (ordinal == -1) continue;
  706. if (spec->ordinals[ordinal])
  707. {
  708. current_line = max( spec->entry_points[i].lineno, spec->ordinals[ordinal]->lineno );
  709. error( "ordinal %d redefined\n%s:%d: First defined here\n",
  710. ordinal, input_file_name,
  711. min( spec->entry_points[i].lineno, spec->ordinals[ordinal]->lineno ) );
  712. }
  713. else spec->ordinals[ordinal] = &spec->entry_points[i];
  714. }
  715. /* now assign ordinals to the rest */
  716. for (i = 0, ordinal = spec->base; i < spec->nb_entry_points; i++)
  717. {
  718. if (spec->entry_points[i].ordinal != -1) continue;
  719. while (spec->ordinals[ordinal]) ordinal++;
  720. if (ordinal >= MAX_ORDINALS)
  721. {
  722. current_line = spec->entry_points[i].lineno;
  723. fatal_error( "Too many functions defined (max %d)\n", MAX_ORDINALS );
  724. }
  725. spec->entry_points[i].ordinal = ordinal;
  726. spec->ordinals[ordinal] = &spec->entry_points[i];
  727. }
  728. if (ordinal > spec->limit) spec->limit = ordinal;
  729. }
  730. /*******************************************************************
  731. * add_16bit_exports
  732. *
  733. * Add the necessary exports to the 32-bit counterpart of a 16-bit module.
  734. */
  735. void add_16bit_exports( DLLSPEC *spec32, DLLSPEC *spec16 )
  736. {
  737. int i;
  738. ORDDEF *odp;
  739. spec32->file_name = xstrdup( spec16->file_name );
  740. spec32->characteristics = IMAGE_FILE_DLL;
  741. spec32->init_func = xstrdup( "DllMain" );
  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. }