1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <ctype.h> 4 #include <string.h> 5 #include <stdarg.h> 6 7 #ifdef _MSC_VER 8 #define strcasecmp(_String1, _String2) _stricmp(_String1, _String2) 9 #define strncasecmp(_String1, _String2, _MaxCount) _strnicmp(_String1, _String2, _MaxCount) 10 #endif 11 12 #define ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0])) 13 14 typedef struct _STRING 15 { 16 const char *buf; 17 int len; 18 } STRING, *PSTRING; 19 20 typedef struct 21 { 22 STRING strName; 23 STRING strTarget; 24 int nCallingConvention; 25 int nOrdinal; 26 int nStackBytes; 27 int nArgCount; 28 int anArgs[30]; 29 unsigned int uFlags; 30 int nNumber; 31 unsigned nStartVersion; 32 unsigned nEndVersion; 33 int bVersionIncluded; 34 } EXPORT; 35 36 #if 0 // Debug helper function 37 void 38 PrintExport(EXPORT *pexp) 39 { 40 fprintf(stderr, "strName='%.*s'\n", pexp->strName.len, pexp->strName.buf); 41 fprintf(stderr, "strName='%.*s'\n", pexp->strTarget.len, pexp->strTarget.buf); 42 fprintf(stderr, "nCallingConvention=%u\n", pexp->nCallingConvention); 43 fprintf(stderr, "nOrdinal=%u\n", pexp->nOrdinal); 44 fprintf(stderr, "nStackBytes=%u\n", pexp->nStackBytes); 45 fprintf(stderr, "nArgCount=%u\n", pexp->nArgCount); 46 fprintf(stderr, "uFlags=0x%x\n", pexp->uFlags); 47 fprintf(stderr, "nNumber=%u\n", pexp->nNumber); 48 fprintf(stderr, "nStartVersion=%u\n", pexp->nStartVersion); 49 fprintf(stderr, "nEndVersion=%u\n", pexp->nEndVersion); 50 fprintf(stderr, "bVersionIncluded=%u\n", pexp->bVersionIncluded); 51 } 52 #endif 53 54 enum _ARCH 55 { 56 ARCH_X86, 57 ARCH_AMD64, 58 ARCH_IA64, 59 ARCH_ARM, 60 ARCH_PPC 61 }; 62 63 typedef int (*PFNOUTLINE)(FILE *, EXPORT *); 64 int gbMSComp = 0; 65 int gbImportLib = 0; 66 int gbNotPrivateNoWarn = 0; 67 int gbTracing = 0; 68 int giArch = ARCH_X86; 69 char *pszArchString = "i386"; 70 char *pszArchString2; 71 char *pszSourceFileName = NULL; 72 char *pszDllName = NULL; 73 char *gpszUnderscore = ""; 74 int gbDebug; 75 unsigned guOsVersion = 0x502; 76 #define DbgPrint(...) (!gbDebug || fprintf(stderr, __VA_ARGS__)) 77 78 enum 79 { 80 FL_PRIVATE = 1, 81 FL_STUB = 2, 82 FL_NONAME = 4, 83 FL_ORDINAL = 8, 84 FL_NORELAY = 16, 85 FL_RET64 = 32, 86 FL_REGISTER = 64, 87 }; 88 89 enum 90 { 91 CC_STDCALL, 92 CC_CDECL, 93 CC_FASTCALL, 94 CC_THISCALL, 95 CC_EXTERN, 96 CC_STUB, 97 }; 98 99 enum 100 { 101 ARG_LONG, 102 ARG_PTR, 103 ARG_STR, 104 ARG_WSTR, 105 ARG_DBL, 106 ARG_INT64, 107 ARG_INT128, 108 ARG_FLOAT 109 }; 110 111 const char* astrCallingConventions[] = 112 { 113 "STDCALL", 114 "CDECL", 115 "FASTCALL", 116 "THISCALL", 117 "EXTERN" 118 }; 119 120 /* 121 * List of OLE exports that should be PRIVATE and not be assigned an ordinal. 122 * In case these conditions are not met when linking with MS LINK.EXE, warnings 123 * LNK4104 and LNK4222 respectively are emitted. 124 */ 125 static const char* astrOlePrivateExports[] = 126 { 127 "DllCanUnloadNow", 128 "DllGetClassObject", 129 "DllGetClassFactoryFromClassString", 130 "DllGetDocumentation", 131 "DllInitialize", 132 "DllInstall", 133 "DllRegisterServer", 134 "DllRegisterServerEx", 135 "DllRegisterServerExW", 136 "DllUnload", 137 "DllUnregisterServer", 138 "RasCustomDeleteEntryNotify", 139 "RasCustomDial", 140 "RasCustomDialDlg", 141 "RasCustomEntryDlg", 142 }; 143 144 static 145 int 146 IsSeparator(char chr) 147 { 148 return ((chr <= ',' && chr != '$' && chr != '#') || 149 (chr >= ':' && chr < '?') ); 150 } 151 152 int 153 CompareToken(const char *token, const char *comparand) 154 { 155 while (*comparand) 156 { 157 if (*token != *comparand) return 0; 158 token++; 159 comparand++; 160 } 161 if (IsSeparator(comparand[-1])) return 1; 162 if (!IsSeparator(*token)) return 0; 163 return 1; 164 } 165 166 const char * 167 ScanToken(const char *token, char chr) 168 { 169 while (!IsSeparator(*token)) 170 { 171 if (*token == chr) return token; 172 token++; 173 } 174 return 0; 175 } 176 177 const char * 178 NextLine(const char *pc) 179 { 180 while (*pc != 0) 181 { 182 if (pc[0] == '\n' && pc[1] == '\r') return pc + 2; 183 else if (pc[0] == '\n') return pc + 1; 184 pc++; 185 } 186 return pc; 187 } 188 189 int 190 TokenLength(const char *pc) 191 { 192 int length = 0; 193 194 while (!IsSeparator(*pc++)) length++; 195 196 return length; 197 } 198 199 const char * 200 NextToken(const char *pc) 201 { 202 /* Skip token */ 203 while (!IsSeparator(*pc)) pc++; 204 205 /* Skip white spaces */ 206 while (*pc == ' ' || *pc == '\t') pc++; 207 208 /* Check for end of line */ 209 if (*pc == '\n' || *pc == '\r' || *pc == 0) return 0; 210 211 /* Check for comment */ 212 if (*pc == '#' || *pc == ';') return 0; 213 214 return pc; 215 } 216 217 void 218 OutputHeader_stub(FILE *file) 219 { 220 fprintf(file, "/* This file is autogenerated, do not edit. */\n\n" 221 "#include <stubs.h>\n"); 222 223 if (gbTracing) 224 { 225 fprintf(file, "#include <wine/debug.h>\n"); 226 fprintf(file, "#include <inttypes.h>\n"); 227 fprintf(file, "WINE_DECLARE_DEBUG_CHANNEL(relay);\n"); 228 } 229 230 fprintf(file, "\n"); 231 } 232 233 int 234 OutputLine_stub(FILE *file, EXPORT *pexp) 235 { 236 int i; 237 int bRelay = 0; 238 int bInPrototype = 0; 239 240 if (pexp->nCallingConvention != CC_STUB && 241 (pexp->uFlags & FL_STUB) == 0) 242 { 243 /* Only relay trace stdcall C functions */ 244 if (!gbTracing || (pexp->nCallingConvention != CC_STDCALL) 245 || (pexp->uFlags & FL_NORELAY) 246 || (pexp->strName.buf[0] == '?')) 247 { 248 return 0; 249 } 250 bRelay = 1; 251 } 252 253 /* Declare the "real" function */ 254 if (bRelay) 255 { 256 fprintf(file, "extern "); 257 bInPrototype = 1; 258 } 259 260 do 261 { 262 if (pexp->uFlags & FL_REGISTER) 263 { 264 /* FIXME: Not sure this is right */ 265 fprintf(file, "void "); 266 } 267 else if (pexp->uFlags & FL_RET64) 268 { 269 fprintf(file, "__int64 "); 270 } 271 else 272 { 273 fprintf(file, "int "); 274 } 275 276 if ((giArch == ARCH_X86) && 277 pexp->nCallingConvention == CC_STDCALL) 278 { 279 fprintf(file, "__stdcall "); 280 } 281 282 /* Check for C++ */ 283 if (pexp->strName.buf[0] == '?') 284 { 285 fprintf(file, "stub_function%d(", pexp->nNumber); 286 } 287 else 288 { 289 if (!bRelay || bInPrototype) 290 fprintf(file, "%.*s(", pexp->strName.len, pexp->strName.buf); 291 else 292 fprintf(file, "$relaytrace$%.*s(", pexp->strName.len, pexp->strName.buf); 293 } 294 295 for (i = 0; i < pexp->nArgCount; i++) 296 { 297 if (i != 0) fprintf(file, ", "); 298 switch (pexp->anArgs[i]) 299 { 300 case ARG_LONG: fprintf(file, "long"); break; 301 case ARG_PTR: fprintf(file, "void*"); break; 302 case ARG_STR: fprintf(file, "char*"); break; 303 case ARG_WSTR: fprintf(file, "wchar_t*"); break; 304 case ARG_DBL: fprintf(file, "double"); break; 305 case ARG_INT64 : fprintf(file, "__int64"); break; 306 /* __int128 is not supported on x86, and int128 in spec files most often represents a GUID */ 307 case ARG_INT128 : fprintf(file, "GUID"); break; 308 case ARG_FLOAT: fprintf(file, "float"); break; 309 } 310 fprintf(file, " a%d", i); 311 } 312 313 if (bInPrototype) 314 { 315 fprintf(file, ");\n\n"); 316 } 317 } while (bInPrototype--); 318 319 if (!bRelay) 320 { 321 fprintf(file, ")\n{\n\tDbgPrint(\"WARNING: calling stub %.*s(", 322 pexp->strName.len, pexp->strName.buf); 323 } 324 else 325 { 326 fprintf(file, ")\n{\n"); 327 if (pexp->uFlags & FL_REGISTER) 328 { 329 /* No return value */ 330 } 331 else if (pexp->uFlags & FL_RET64) 332 { 333 fprintf(file, "\t__int64 retval;\n"); 334 } 335 else 336 { 337 fprintf(file, "\tint retval;\n"); 338 } 339 fprintf(file, "\tif (TRACE_ON(relay))\n\t\tDPRINTF(\"%s: %.*s(", 340 pszDllName, pexp->strName.len, pexp->strName.buf); 341 } 342 343 for (i = 0; i < pexp->nArgCount; i++) 344 { 345 if (i != 0) fprintf(file, ","); 346 switch (pexp->anArgs[i]) 347 { 348 case ARG_LONG: fprintf(file, "0x%%lx"); break; 349 case ARG_PTR: fprintf(file, "0x%%p"); break; 350 case ARG_STR: fprintf(file, "'%%s'"); break; 351 case ARG_WSTR: fprintf(file, "'%%ws'"); break; 352 case ARG_DBL: fprintf(file, "%%f"); break; 353 case ARG_INT64: fprintf(file, "%%\"PRIx64\""); break; 354 case ARG_INT128: fprintf(file, "'%%s'"); break; 355 case ARG_FLOAT: fprintf(file, "%%f"); break; 356 } 357 } 358 fprintf(file, ")\\n\""); 359 360 for (i = 0; i < pexp->nArgCount; i++) 361 { 362 fprintf(file, ", "); 363 switch (pexp->anArgs[i]) 364 { 365 case ARG_LONG: fprintf(file, "(long)a%d", i); break; 366 case ARG_PTR: fprintf(file, "(void*)a%d", i); break; 367 case ARG_STR: fprintf(file, "(char*)a%d", i); break; 368 case ARG_WSTR: fprintf(file, "(wchar_t*)a%d", i); break; 369 case ARG_DBL: fprintf(file, "(double)a%d", i); break; 370 case ARG_INT64: fprintf(file, "(__int64)a%d", i); break; 371 case ARG_INT128: fprintf(file, "wine_dbgstr_guid(&a%d)", i); break; 372 case ARG_FLOAT: fprintf(file, "(float)a%d", i); break; 373 } 374 } 375 fprintf(file, ");\n"); 376 377 if (pexp->nCallingConvention == CC_STUB) 378 { 379 fprintf(file, "\t__wine_spec_unimplemented_stub(\"%s\", __FUNCTION__);\n", pszDllName); 380 } 381 else if (bRelay) 382 { 383 if (pexp->uFlags & FL_REGISTER) 384 { 385 fprintf(file,"\t"); 386 } 387 else 388 { 389 fprintf(file, "\tretval = "); 390 } 391 fprintf(file, "%.*s(", pexp->strName.len, pexp->strName.buf); 392 393 for (i = 0; i < pexp->nArgCount; i++) 394 { 395 if (i != 0) fprintf(file, ", "); 396 fprintf(file, "a%d", i); 397 } 398 fprintf(file, ");\n"); 399 } 400 401 if (!bRelay) 402 fprintf(file, "\treturn 0;\n}\n\n"); 403 else if ((pexp->uFlags & FL_REGISTER) == 0) 404 { 405 if (pexp->uFlags & FL_RET64) 406 { 407 fprintf(file, "\tif (TRACE_ON(relay))\n\t\tDPRINTF(\"%s: %.*s: retval = %%\"PRIx64\"\\n\", retval);\n", 408 pszDllName, pexp->strName.len, pexp->strName.buf); 409 } 410 else 411 { 412 fprintf(file, "\tif (TRACE_ON(relay))\n\t\tDPRINTF(\"%s: %.*s: retval = 0x%%lx\\n\", retval);\n", 413 pszDllName, pexp->strName.len, pexp->strName.buf); 414 } 415 fprintf(file, "\treturn retval;\n}\n\n"); 416 } 417 418 return 1; 419 } 420 421 void 422 OutputHeader_asmstub(FILE *file, char *libname) 423 { 424 fprintf(file, "; File generated automatically, do not edit! \n\n"); 425 426 if (giArch == ARCH_X86) 427 { 428 fprintf(file, ".586\n.model flat\n.code\n"); 429 } 430 else if (giArch == ARCH_AMD64) 431 { 432 fprintf(file, ".code\n"); 433 } 434 else if (giArch == ARCH_ARM) 435 { 436 fprintf(file, " AREA |.text|,ALIGN=2,CODE,READONLY\n\n"); 437 } 438 } 439 440 void 441 Output_stublabel(FILE *fileDest, char* pszSymbolName) 442 { 443 if (giArch == ARCH_ARM) 444 { 445 fprintf(fileDest, 446 "\tEXPORT |%s| [FUNC]\n|%s|\n", 447 pszSymbolName, 448 pszSymbolName); 449 } 450 else 451 { 452 fprintf(fileDest, 453 "PUBLIC %s\n%s: nop\n", 454 pszSymbolName, 455 pszSymbolName); 456 } 457 } 458 459 int 460 OutputLine_asmstub(FILE *fileDest, EXPORT *pexp) 461 { 462 char szNameBuffer[128]; 463 464 /* Handle autoname */ 465 if (pexp->strName.len == 1 && pexp->strName.buf[0] == '@') 466 { 467 sprintf(szNameBuffer, "%s_stub_ordinal%d", 468 gpszUnderscore, pexp->nOrdinal); 469 } 470 else if (giArch != ARCH_X86) 471 { 472 /* Does the string already have stdcall decoration? */ 473 const char *pcAt = ScanToken(pexp->strName.buf, '@'); 474 if (pcAt && (pcAt < (pexp->strName.buf + pexp->strName.len)) && 475 (pexp->strName.buf[0] == '_')) 476 { 477 /* Skip leading underscore and remove trailing decoration */ 478 sprintf(szNameBuffer, "_stub_%.*s", 479 (int)(pcAt - pexp->strName.buf - 1), 480 pexp->strName.buf + 1); 481 } 482 else 483 { 484 sprintf(szNameBuffer, "_stub_%.*s", 485 pexp->strName.len, pexp->strName.buf); 486 } 487 } 488 else if (pexp->nCallingConvention == CC_STDCALL) 489 { 490 sprintf(szNameBuffer, "__stub_%.*s@%d", 491 pexp->strName.len, pexp->strName.buf, pexp->nStackBytes); 492 } 493 else if (pexp->nCallingConvention == CC_FASTCALL) 494 { 495 sprintf(szNameBuffer, "@_stub_%.*s@%d", 496 pexp->strName.len, pexp->strName.buf, pexp->nStackBytes); 497 } 498 else if ((pexp->nCallingConvention == CC_CDECL) || 499 (pexp->nCallingConvention == CC_THISCALL) || 500 (pexp->nCallingConvention == CC_EXTERN) || 501 (pexp->nCallingConvention == CC_STUB)) 502 { 503 sprintf(szNameBuffer, "__stub_%.*s", 504 pexp->strName.len, pexp->strName.buf); 505 } 506 else 507 { 508 fprintf(stderr, "Invalid calling convention"); 509 return 0; 510 } 511 512 Output_stublabel(fileDest, szNameBuffer); 513 514 return 1; 515 } 516 517 void 518 OutputHeader_def(FILE *file, char *libname) 519 { 520 fprintf(file, 521 "; File generated automatically, do not edit!\n\n" 522 "NAME %s\n\n" 523 "EXPORTS\n", 524 libname); 525 } 526 527 void 528 PrintName(FILE *fileDest, EXPORT *pexp, PSTRING pstr, int fDeco) 529 { 530 const char *pcName = pstr->buf; 531 int nNameLength = pstr->len; 532 const char* pcDot, *pcAt; 533 char namebuffer[19]; 534 535 if ((nNameLength == 1) && (pcName[0] == '@')) 536 { 537 sprintf(namebuffer, "ordinal%d", pexp->nOrdinal); 538 pcName = namebuffer; 539 nNameLength = strlen(namebuffer); 540 } 541 542 /* Check for non-x86 first */ 543 if (giArch != ARCH_X86) 544 { 545 /* Does the string already have stdcall decoration? */ 546 pcAt = ScanToken(pcName, '@'); 547 if (pcAt && (pcAt < (pcName + nNameLength)) && (pcName[0] == '_')) 548 { 549 /* Skip leading underscore and remove trailing decoration */ 550 pcName++; 551 nNameLength = (int)(pcAt - pcName); 552 } 553 554 /* Print the undecorated function name */ 555 fprintf(fileDest, "%.*s", nNameLength, pcName); 556 } 557 else if (fDeco && 558 ((pexp->nCallingConvention == CC_STDCALL) || 559 (pexp->nCallingConvention == CC_FASTCALL))) 560 { 561 /* Scan for a dll forwarding dot */ 562 pcDot = ScanToken(pcName, '.'); 563 if (pcDot) 564 { 565 /* First print the dll name, followed by a dot */ 566 nNameLength = (int)(pcDot - pcName); 567 fprintf(fileDest, "%.*s.", nNameLength, pcName); 568 569 /* Now the actual function name */ 570 pcName = pcDot + 1; 571 nNameLength = pexp->strTarget.len - nNameLength - 1; 572 } 573 574 /* Does the string already have decoration? */ 575 pcAt = ScanToken(pcName, '@'); 576 if (pcAt && (pcAt < (pcName + nNameLength))) 577 { 578 /* On GCC, we need to remove the leading stdcall underscore */ 579 if (!gbMSComp && (pexp->nCallingConvention == CC_STDCALL)) 580 { 581 pcName++; 582 nNameLength--; 583 } 584 585 /* Print the already decorated function name */ 586 fprintf(fileDest, "%.*s", nNameLength, pcName); 587 } 588 else 589 { 590 /* Print the prefix, but skip it for (GCC && stdcall) */ 591 if (gbMSComp || (pexp->nCallingConvention != CC_STDCALL)) 592 { 593 fprintf(fileDest, "%c", pexp->nCallingConvention == CC_FASTCALL ? '@' : '_'); 594 } 595 596 /* Print the name with trailing decoration */ 597 fprintf(fileDest, "%.*s@%d", nNameLength, pcName, pexp->nStackBytes); 598 } 599 } 600 else 601 { 602 /* Print the undecorated function name */ 603 fprintf(fileDest, "%.*s", nNameLength, pcName); 604 } 605 } 606 607 void 608 OutputLine_def_MS(FILE *fileDest, EXPORT *pexp) 609 { 610 PrintName(fileDest, pexp, &pexp->strName, 0); 611 612 if (gbImportLib) 613 { 614 /* Redirect to a stub function, to get the right decoration in the lib */ 615 fprintf(fileDest, "=_stub_"); 616 PrintName(fileDest, pexp, &pexp->strName, 0); 617 } 618 else if (pexp->strTarget.buf) 619 { 620 if (pexp->strName.buf[0] == '?') 621 { 622 //fprintf(stderr, "warning: ignoring C++ redirection %.*s -> %.*s\n", 623 // pexp->strName.len, pexp->strName.buf, pexp->strTarget.len, pexp->strTarget.buf); 624 } 625 else 626 { 627 fprintf(fileDest, "="); 628 629 /* If the original name was decorated, use decoration in the forwarder as well */ 630 if ((giArch == ARCH_X86) && ScanToken(pexp->strName.buf, '@') && 631 !ScanToken(pexp->strTarget.buf, '@') && 632 ((pexp->nCallingConvention == CC_STDCALL) || 633 (pexp->nCallingConvention == CC_FASTCALL)) ) 634 { 635 PrintName(fileDest, pexp, &pexp->strTarget, 1); 636 } 637 else 638 { 639 /* Write the undecorated redirection name */ 640 fprintf(fileDest, "%.*s", pexp->strTarget.len, pexp->strTarget.buf); 641 } 642 } 643 } 644 else if (((pexp->uFlags & FL_STUB) || (pexp->nCallingConvention == CC_STUB)) && 645 (pexp->strName.buf[0] == '?')) 646 { 647 /* C++ stubs are forwarded to C stubs */ 648 fprintf(fileDest, "=stub_function%d", pexp->nNumber); 649 } 650 else if (gbTracing && ((pexp->uFlags & FL_NORELAY) == 0) && (pexp->nCallingConvention == CC_STDCALL) && 651 (pexp->strName.buf[0] != '?')) 652 { 653 /* Redirect it to the relay-tracing trampoline */ 654 fprintf(fileDest, "=$relaytrace$%.*s", pexp->strName.len, pexp->strName.buf); 655 } 656 } 657 658 void 659 OutputLine_def_GCC(FILE *fileDest, EXPORT *pexp) 660 { 661 int bTracing = 0; 662 /* Print the function name, with decoration for export libs */ 663 PrintName(fileDest, pexp, &pexp->strName, gbImportLib); 664 DbgPrint("Generating def line for '%.*s'\n", pexp->strName.len, pexp->strName.buf); 665 666 /* Check if this is a forwarded export */ 667 if (pexp->strTarget.buf) 668 { 669 int fIsExternal = !!ScanToken(pexp->strTarget.buf, '.'); 670 DbgPrint("Got redirect '%.*s'\n", pexp->strTarget.len, pexp->strTarget.buf); 671 672 /* print the target name, don't decorate if it is external */ 673 fprintf(fileDest, "="); 674 PrintName(fileDest, pexp, &pexp->strTarget, !fIsExternal); 675 } 676 else if (((pexp->uFlags & FL_STUB) || (pexp->nCallingConvention == CC_STUB)) && 677 (pexp->strName.buf[0] == '?')) 678 { 679 /* C++ stubs are forwarded to C stubs */ 680 fprintf(fileDest, "=stub_function%d", pexp->nNumber); 681 } 682 else if (gbTracing && ((pexp->uFlags & FL_NORELAY) == 0) && 683 (pexp->nCallingConvention == CC_STDCALL) && 684 (pexp->strName.buf[0] != '?')) 685 { 686 /* Redirect it to the relay-tracing trampoline */ 687 char buf[256]; 688 STRING strTarget; 689 fprintf(fileDest, "="); 690 sprintf(buf, "$relaytrace$%.*s", pexp->strName.len, pexp->strName.buf); 691 strTarget.buf = buf; 692 strTarget.len = pexp->strName.len + 12; 693 PrintName(fileDest, pexp, &strTarget, 1); 694 bTracing = 1; 695 } 696 697 /* Special handling for stdcall and fastcall */ 698 if ((giArch == ARCH_X86) && 699 ((pexp->nCallingConvention == CC_STDCALL) || 700 (pexp->nCallingConvention == CC_FASTCALL))) 701 { 702 /* Is this the import lib? */ 703 if (gbImportLib) 704 { 705 /* Is the name in the spec file decorated? */ 706 const char* pcDeco = ScanToken(pexp->strName.buf, '@'); 707 if (pcDeco && 708 (pexp->strName.len > 1) && 709 (pcDeco < pexp->strName.buf + pexp->strName.len)) 710 { 711 /* Write the name including the leading @ */ 712 fprintf(fileDest, "==%.*s", pexp->strName.len, pexp->strName.buf); 713 } 714 } 715 else if ((!pexp->strTarget.buf) && !(bTracing)) 716 { 717 /* Write a forwarder to the actual decorated symbol */ 718 fprintf(fileDest, "="); 719 PrintName(fileDest, pexp, &pexp->strName, 1); 720 } 721 } 722 } 723 724 int 725 OutputLine_def(FILE *fileDest, EXPORT *pexp) 726 { 727 DbgPrint("OutputLine_def: '%.*s'...\n", pexp->strName.len, pexp->strName.buf); 728 fprintf(fileDest, " "); 729 730 if (gbMSComp) 731 OutputLine_def_MS(fileDest, pexp); 732 else 733 OutputLine_def_GCC(fileDest, pexp); 734 735 /* On GCC builds we force ordinals */ 736 if ((pexp->uFlags & FL_ORDINAL) || (!gbMSComp && !gbImportLib)) 737 { 738 fprintf(fileDest, " @%d", pexp->nOrdinal); 739 } 740 741 if (pexp->uFlags & FL_NONAME) 742 { 743 fprintf(fileDest, " NONAME"); 744 } 745 746 /* Either PRIVATE or DATA */ 747 if (pexp->uFlags & FL_PRIVATE) 748 { 749 fprintf(fileDest, " PRIVATE"); 750 } 751 else if (pexp->nCallingConvention == CC_EXTERN) 752 { 753 fprintf(fileDest, " DATA"); 754 } 755 756 fprintf(fileDest, "\n"); 757 758 return 1; 759 } 760 761 void 762 Fatalv( 763 const char* filename, 764 unsigned nLine, 765 const char *pcLine, 766 const char *pc, 767 size_t errorlen, 768 const char *format, 769 va_list argptr) 770 { 771 unsigned i, errorpos, len; 772 const char* pcLineEnd; 773 774 /* Get the length of the line */ 775 pcLineEnd = strpbrk(pcLine, "\r\n"); 776 len = (unsigned)(pcLineEnd - pcLine); 777 778 if (pc == NULL) 779 { 780 pc = pcLine + len - 1; 781 errorlen = 1; 782 } 783 784 errorpos = (unsigned)(pc - pcLine); 785 786 /* Output the error message */ 787 fprintf(stderr, "ERROR: (%s:%u:%u): ", filename, nLine, errorpos); 788 vfprintf(stderr, format, argptr); 789 fprintf(stderr, "\n"); 790 791 /* Output the line with the error */ 792 fprintf(stderr, "> %.*s\n", len, pcLine); 793 794 if (errorlen == 0) 795 { 796 errorlen = TokenLength(pc); 797 } 798 799 for (i = 0; i < errorpos + 2; i++) 800 { 801 fprintf(stderr, " "); 802 } 803 for (i = 0; i < errorlen; i++) 804 { 805 fprintf(stderr, "~"); 806 } 807 fprintf(stderr, "\n"); 808 exit(-1); 809 } 810 811 void 812 Fatal( 813 const char* filename, 814 unsigned nLine, 815 const char *pcLine, 816 const char *pc, 817 size_t errorlen, 818 const char *format, 819 ...) 820 { 821 va_list argptr; 822 823 va_start(argptr, format); 824 Fatalv(filename, nLine, pcLine, pc, errorlen, format, argptr); 825 va_end(argptr); 826 } 827 828 EXPORT * 829 ParseFile(char* pcStart, FILE *fileDest, unsigned *cExports) 830 { 831 EXPORT *pexports; 832 const char *pc, *pcLine; 833 int cLines, nLine; 834 EXPORT exp; 835 int included; 836 unsigned int i; 837 838 *cExports = 0; 839 840 //fprintf(stderr, "info: line %d, pcStart:'%.30s'\n", nLine, pcStart); 841 842 /* Count the lines */ 843 for (cLines = 1, pcLine = pcStart; *pcLine; pcLine = NextLine(pcLine), cLines++) 844 { 845 /* Nothing */ 846 } 847 848 /* Allocate an array of EXPORT structures */ 849 pexports = malloc(cLines * sizeof(EXPORT)); 850 if (pexports == NULL) 851 { 852 fprintf(stderr, "ERROR: %s: failed to allocate EXPORT array of %u elements\n", pszSourceFileName, cLines); 853 return NULL; 854 } 855 856 /* Loop all lines */ 857 nLine = 1; 858 exp.nNumber = 0; 859 for (pcLine = pcStart; *pcLine; pcLine = NextLine(pcLine), nLine++) 860 { 861 pc = pcLine; 862 863 exp.strName.buf = NULL; 864 exp.strName.len = 0; 865 exp.strTarget.buf = NULL; 866 exp.strTarget.len = 0; 867 exp.nArgCount = 0; 868 exp.uFlags = 0; 869 exp.nNumber++; 870 exp.nStartVersion = 0; 871 exp.nEndVersion = 0xFFFFFFFF; 872 exp.bVersionIncluded = 1; 873 874 /* Skip white spaces */ 875 while (*pc == ' ' || *pc == '\t') pc++; 876 877 /* Check for line break or comment */ 878 if ((*pc == '\r') || (*pc == '\n') || 879 (*pc == ';') || (*pc == '#')) 880 { 881 continue; 882 } 883 884 /* On EOF we are done */ 885 if (*pc == 0) 886 { 887 return pexports; 888 } 889 890 /* Now we should get either an ordinal or @ */ 891 if (*pc == '@') 892 { 893 exp.nOrdinal = -1; 894 } 895 else if ((*pc >= '0') && (*pc <= '9')) 896 { 897 char* end; 898 long int number = strtol(pc, &end, 10); 899 if ((*end != ' ') && (*end != '\t')) 900 { 901 Fatal(pszSourceFileName, nLine, pcLine, end, 0, "Unexpected character(s) after ordinal"); 902 } 903 904 if ((number < 0) || (number > 0xFFFE)) 905 { 906 Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Invalid value for ordinal"); 907 } 908 909 exp.nOrdinal = number; 910 911 /* The import lib should contain the ordinal only if -ordinal was specified */ 912 if (!gbImportLib) 913 exp.uFlags |= FL_ORDINAL; 914 } 915 else 916 { 917 Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Expected '@' or ordinal"); 918 } 919 920 /* Go to next token (type) */ 921 if (!(pc = NextToken(pc))) 922 { 923 Fatal(pszSourceFileName, nLine, pcLine, pc, 1, "Unexpected end of line"); 924 } 925 926 //fprintf(stderr, "info: Token:'%.*s'\n", TokenLength(pc), pc); 927 928 /* Now we should get the type */ 929 if (CompareToken(pc, "stdcall")) 930 { 931 exp.nCallingConvention = CC_STDCALL; 932 } 933 else if (CompareToken(pc, "cdecl") || 934 CompareToken(pc, "varargs")) 935 { 936 exp.nCallingConvention = CC_CDECL; 937 } 938 else if (CompareToken(pc, "fastcall")) 939 { 940 exp.nCallingConvention = CC_FASTCALL; 941 } 942 else if (CompareToken(pc, "thiscall")) 943 { 944 exp.nCallingConvention = CC_THISCALL; 945 } 946 else if (CompareToken(pc, "extern")) 947 { 948 exp.nCallingConvention = CC_EXTERN; 949 } 950 else if (CompareToken(pc, "stub")) 951 { 952 exp.nCallingConvention = CC_STUB; 953 } 954 else 955 { 956 Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Invalid calling convention"); 957 } 958 959 /* Go to next token (options or name) */ 960 if (!(pc = NextToken(pc))) 961 { 962 Fatal(pszSourceFileName, nLine, pcLine, pc, 1, "Unexpected end of line"); 963 } 964 965 /* Handle options */ 966 included = 1; 967 while (*pc == '-') 968 { 969 if (CompareToken(pc, "-arch=")) 970 { 971 /* Default to not included */ 972 included = 0; 973 pc += 5; 974 975 /* Look if we are included */ 976 do 977 { 978 pc++; 979 if (CompareToken(pc, pszArchString) || 980 CompareToken(pc, pszArchString2)) 981 { 982 included = 1; 983 } 984 985 /* Skip to next arch or end */ 986 while (*pc > ',') pc++; 987 } while (*pc == ','); 988 } 989 else if (CompareToken(pc, "-i386")) 990 { 991 if (giArch != ARCH_X86) included = 0; 992 } 993 else if (CompareToken(pc, "-version=")) 994 { 995 const char *pcVersionStart = pc + 9; 996 997 /* Default to not included */ 998 exp.bVersionIncluded = 0; 999 pc += 8; 1000 1001 /* Look if we are included */ 1002 do 1003 { 1004 unsigned version, endversion; 1005 1006 /* Optionally skip leading '0x' */ 1007 pc++; 1008 if ((pc[0] == '0') && (pc[1] == 'x')) pc += 2; 1009 1010 /* Now get the version number */ 1011 endversion = version = strtoul(pc, (char**)&pc, 16); 1012 1013 /* Check if it's a range */ 1014 if (pc[0] == '+') 1015 { 1016 endversion = 0xFFF; 1017 pc++; 1018 } 1019 else if (pc[0] == '-') 1020 { 1021 /* Optionally skip leading '0x' */ 1022 pc++; 1023 if ((pc[0] == '0') && (pc[1] == 'x')) pc += 2; 1024 endversion = strtoul(pc, (char**)&pc, 16); 1025 } 1026 1027 /* Check for degenerate range */ 1028 if (version > endversion) 1029 { 1030 Fatal(pszSourceFileName, 1031 nLine, 1032 pcLine, 1033 pcVersionStart, 1034 pc - pcVersionStart, 1035 "Invalid version range"); 1036 } 1037 1038 exp.nStartVersion = version; 1039 exp.nEndVersion = endversion; 1040 1041 /* Now compare the range with our version */ 1042 if ((guOsVersion >= version) && 1043 (guOsVersion <= endversion)) 1044 { 1045 exp.bVersionIncluded = 1; 1046 } 1047 1048 /* Skip to next arch or end */ 1049 while (*pc > ',') pc++; 1050 1051 } while (*pc == ','); 1052 } 1053 else if (CompareToken(pc, "-private")) 1054 { 1055 exp.uFlags |= FL_PRIVATE; 1056 } 1057 else if (CompareToken(pc, "-noname")) 1058 { 1059 exp.uFlags |= FL_ORDINAL | FL_NONAME; 1060 } 1061 else if (CompareToken(pc, "-ordinal")) 1062 { 1063 exp.uFlags |= FL_ORDINAL; 1064 /* GCC doesn't automatically import by ordinal if an ordinal 1065 * is found in the def file. Force it. */ 1066 if (gbImportLib && !gbMSComp) 1067 exp.uFlags |= FL_NONAME; 1068 } 1069 else if (CompareToken(pc, "-stub")) 1070 { 1071 exp.uFlags |= FL_STUB; 1072 } 1073 else if (CompareToken(pc, "-norelay")) 1074 { 1075 exp.uFlags |= FL_NORELAY; 1076 } 1077 else if (CompareToken(pc, "-ret64")) 1078 { 1079 exp.uFlags |= FL_RET64; 1080 } 1081 else if (CompareToken(pc, "-register")) 1082 { 1083 exp.uFlags |= FL_REGISTER; 1084 } 1085 else 1086 { 1087 fprintf(stdout, 1088 "INFO: %s line %d: Ignored option: '%.*s'\n", 1089 pszSourceFileName, 1090 nLine, 1091 TokenLength(pc), 1092 pc); 1093 } 1094 1095 /* Go to next token */ 1096 pc = NextToken(pc); 1097 } 1098 1099 //fprintf(stderr, "info: Name:'%.10s'\n", pc); 1100 1101 /* If arch didn't match ours, skip this entry */ 1102 if (!included) continue; 1103 1104 /* Get name */ 1105 exp.strName.buf = pc; 1106 exp.strName.len = TokenLength(pc); 1107 //DbgPrint("Got name: '%.*s'\n", exp.strName.len, exp.strName.buf); 1108 1109 /* Check for autoname */ 1110 if ((exp.strName.len == 1) && (exp.strName.buf[0] == '@')) 1111 { 1112 exp.uFlags |= FL_ORDINAL | FL_NONAME; 1113 } 1114 1115 /* Handle parameters */ 1116 exp.nStackBytes = 0; 1117 if (exp.nCallingConvention != CC_EXTERN && 1118 exp.nCallingConvention != CC_STUB) 1119 { 1120 /* Go to next token */ 1121 if (!(pc = NextToken(pc))) 1122 { 1123 Fatal(pszSourceFileName, nLine, pcLine, pc, 1, "Unexpected end of line"); 1124 } 1125 1126 /* Verify syntax */ 1127 if (*pc++ != '(') 1128 { 1129 Fatal(pszSourceFileName, nLine, pcLine, pc - 1, 0, "Expected '('"); 1130 } 1131 1132 /* Skip whitespaces */ 1133 while (*pc == ' ' || *pc == '\t') pc++; 1134 1135 exp.nStackBytes = 0; 1136 while (*pc >= '0') 1137 { 1138 if (CompareToken(pc, "long")) 1139 { 1140 exp.nStackBytes += 4; 1141 exp.anArgs[exp.nArgCount] = ARG_LONG; 1142 } 1143 else if (CompareToken(pc, "double")) 1144 { 1145 exp.nStackBytes += 8; 1146 exp.anArgs[exp.nArgCount] = ARG_DBL; 1147 } 1148 else if (CompareToken(pc, "ptr")) 1149 { 1150 exp.nStackBytes += 4; // sizeof(void*) on x86 1151 exp.anArgs[exp.nArgCount] = ARG_PTR; 1152 } 1153 else if (CompareToken(pc, "str")) 1154 { 1155 exp.nStackBytes += 4; // sizeof(void*) on x86 1156 exp.anArgs[exp.nArgCount] = ARG_STR; 1157 } 1158 else if (CompareToken(pc, "wstr")) 1159 { 1160 exp.nStackBytes += 4; // sizeof(void*) on x86 1161 exp.anArgs[exp.nArgCount] = ARG_WSTR; 1162 } 1163 else if (CompareToken(pc, "int64")) 1164 { 1165 exp.nStackBytes += 8; 1166 exp.anArgs[exp.nArgCount] = ARG_INT64; 1167 } 1168 else if (CompareToken(pc, "int128")) 1169 { 1170 exp.nStackBytes += 16; 1171 exp.anArgs[exp.nArgCount] = ARG_INT128; 1172 } 1173 else if (CompareToken(pc, "float")) 1174 { 1175 exp.nStackBytes += 4; 1176 exp.anArgs[exp.nArgCount] = ARG_FLOAT; 1177 } 1178 else 1179 { 1180 Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Unrecognized type"); 1181 } 1182 1183 exp.nArgCount++; 1184 1185 /* Go to next parameter */ 1186 if (!(pc = NextToken(pc))) 1187 { 1188 Fatal(pszSourceFileName, nLine, pcLine, pc, 1, "Unexpected end of line"); 1189 } 1190 } 1191 1192 /* Check syntax */ 1193 if (*pc++ != ')') 1194 { 1195 Fatal(pszSourceFileName, nLine, pcLine, pc - 1, 0, "Expected ')'"); 1196 } 1197 } 1198 1199 /* Handle special stub cases */ 1200 if (exp.nCallingConvention == CC_STUB) 1201 { 1202 /* Check for c++ mangled name */ 1203 if (pc[0] == '?') 1204 { 1205 //printf("Found c++ mangled name...\n"); 1206 // 1207 } 1208 else 1209 { 1210 /* Check for stdcall name */ 1211 const char *p = ScanToken(pc, '@'); 1212 if (p && (p - pc < exp.strName.len)) 1213 { 1214 int i; 1215 1216 /* Truncate the name to before the @ */ 1217 exp.strName.len = (int)(p - pc); 1218 if (exp.strName.len < 1) 1219 { 1220 Fatal(pszSourceFileName, nLine, pcLine, p, 1, "Unexpected @"); 1221 } 1222 exp.nStackBytes = atoi(p + 1); 1223 exp.nArgCount = exp.nStackBytes / 4; 1224 exp.nCallingConvention = CC_STDCALL; 1225 exp.uFlags |= FL_STUB; 1226 for (i = 0; i < exp.nArgCount; i++) 1227 exp.anArgs[i] = ARG_LONG; 1228 } 1229 } 1230 } 1231 1232 /* Get optional redirection */ 1233 pc = NextToken(pc); 1234 if (pc) 1235 { 1236 exp.strTarget.buf = pc; 1237 exp.strTarget.len = TokenLength(pc); 1238 1239 /* Check syntax (end of line) */ 1240 if (NextToken(pc)) 1241 { 1242 Fatal(pszSourceFileName, nLine, pcLine, NextToken(pc), 0, "Excess token(s) at end of definition"); 1243 } 1244 1245 /* Don't relay-trace forwarded functions */ 1246 exp.uFlags |= FL_NORELAY; 1247 } 1248 else 1249 { 1250 exp.strTarget.buf = NULL; 1251 exp.strTarget.len = 0; 1252 } 1253 1254 /* Check for no-name without ordinal */ 1255 if ((exp.uFlags & FL_ORDINAL) && (exp.nOrdinal == -1)) 1256 { 1257 Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Ordinal export without ordinal"); 1258 } 1259 1260 /* 1261 * Check for special handling of OLE exports, only when MSVC 1262 * is not used, since otherwise this is handled by MS LINK.EXE. 1263 */ 1264 if (!gbMSComp) 1265 { 1266 /* Check whether the current export is not PRIVATE, or has an ordinal */ 1267 int bIsNotPrivate = (!gbNotPrivateNoWarn && /*gbImportLib &&*/ !(exp.uFlags & FL_PRIVATE)); 1268 int bHasOrdinal = (exp.uFlags & FL_ORDINAL); 1269 1270 /* Check whether the current export is an OLE export, in case any of these tests pass */ 1271 if (bIsNotPrivate || bHasOrdinal) 1272 { 1273 for (i = 0; i < ARRAYSIZE(astrOlePrivateExports); ++i) 1274 { 1275 if (strlen(astrOlePrivateExports[i]) == exp.strName.len && 1276 strncmp(exp.strName.buf, astrOlePrivateExports[i], exp.strName.len) == 0) 1277 { 1278 /* The current export is an OLE export: display the corresponding warning */ 1279 if (bIsNotPrivate) 1280 { 1281 fprintf(stderr, "WARNING: %s line %d: Exported symbol '%.*s' should be PRIVATE\n", 1282 pszSourceFileName, nLine, exp.strName.len, exp.strName.buf); 1283 } 1284 if (bHasOrdinal) 1285 { 1286 fprintf(stderr, "WARNING: %s line %d: exported symbol '%.*s' should not be assigned an ordinal\n", 1287 pszSourceFileName, nLine, exp.strName.len, exp.strName.buf); 1288 } 1289 break; 1290 } 1291 } 1292 } 1293 } 1294 1295 pexports[*cExports] = exp; 1296 (*cExports)++; 1297 gbDebug = 0; 1298 } 1299 1300 return pexports; 1301 } 1302 1303 int 1304 ApplyOrdinals(EXPORT* pexports, unsigned cExports) 1305 { 1306 unsigned short i, j; 1307 char* used; 1308 1309 /* Allocate a table to mark used ordinals */ 1310 used = malloc(65536); 1311 if (used == NULL) 1312 { 1313 fprintf(stderr, "Failed to allocate memory for ordinal use table\n"); 1314 return -1; 1315 } 1316 memset(used, 0, 65536); 1317 1318 /* Pass 1: mark the ordinals that are already used */ 1319 for (i = 0; i < cExports; i++) 1320 { 1321 if (pexports[i].uFlags & FL_ORDINAL) 1322 { 1323 if (used[pexports[i].nOrdinal] != 0) 1324 { 1325 fprintf(stderr, "Found duplicate ordinal: %u\n", pexports[i].nOrdinal); 1326 return -1; 1327 } 1328 used[pexports[i].nOrdinal] = 1; 1329 } 1330 } 1331 1332 /* Pass 2: apply available ordinals */ 1333 for (i = 0, j = 1; i < cExports; i++) 1334 { 1335 if ((pexports[i].uFlags & FL_ORDINAL) == 0 && pexports[i].bVersionIncluded) 1336 { 1337 while (used[j] != 0) 1338 j++; 1339 1340 pexports[i].nOrdinal = j; 1341 used[j] = 1; 1342 } 1343 } 1344 1345 free(used); 1346 return 0; 1347 } 1348 1349 void usage(void) 1350 { 1351 printf("syntax: spec2def [<options> ...] <spec file>\n" 1352 "Possible options:\n" 1353 " -h --help print this help screen\n" 1354 " -l=<file> generate an asm lib stub\n" 1355 " -d=<file> generate a def file\n" 1356 " -s=<file> generate a stub file\n" 1357 " --ms MSVC compatibility\n" 1358 " -n=<name> name of the dll\n" 1359 " --implib generate a def file for an import library\n" 1360 " --no-private-warnings suppress warnings about symbols that should be -private\n" 1361 " -a=<arch> set architecture to <arch> (i386, x86_64, arm)\n" 1362 " --with-tracing generate wine-like \"+relay\" trace trampolines (needs -s)\n"); 1363 } 1364 1365 int main(int argc, char *argv[]) 1366 { 1367 size_t nFileSize; 1368 char *pszSource, *pszDefFileName = NULL, *pszStubFileName = NULL, *pszLibStubName = NULL; 1369 const char* pszVersionOption = "--version=0x"; 1370 char achDllName[40]; 1371 FILE *file; 1372 unsigned cExports = 0, i; 1373 EXPORT *pexports; 1374 1375 if (argc < 2) 1376 { 1377 usage(); 1378 return -1; 1379 } 1380 1381 /* Read options */ 1382 for (i = 1; i < (unsigned)argc && *argv[i] == '-'; i++) 1383 { 1384 if ((strcasecmp(argv[i], "--help") == 0) || 1385 (strcasecmp(argv[i], "-h") == 0)) 1386 { 1387 usage(); 1388 return 0; 1389 } 1390 else if (argv[i][1] == 'd' && argv[i][2] == '=') 1391 { 1392 pszDefFileName = argv[i] + 3; 1393 } 1394 else if (argv[i][1] == 'l' && argv[i][2] == '=') 1395 { 1396 pszLibStubName = argv[i] + 3; 1397 } 1398 else if (argv[i][1] == 's' && argv[i][2] == '=') 1399 { 1400 pszStubFileName = argv[i] + 3; 1401 } 1402 else if (argv[i][1] == 'n' && argv[i][2] == '=') 1403 { 1404 pszDllName = argv[i] + 3; 1405 } 1406 else if (strncasecmp(argv[i], pszVersionOption, strlen(pszVersionOption)) == 0) 1407 { 1408 guOsVersion = strtoul(argv[i] + strlen(pszVersionOption), NULL, 16); 1409 } 1410 else if (strcasecmp(argv[i], "--implib") == 0) 1411 { 1412 gbImportLib = 1; 1413 } 1414 else if (strcasecmp(argv[i], "--ms") == 0) 1415 { 1416 gbMSComp = 1; 1417 } 1418 else if (strcasecmp(argv[i], "--no-private-warnings") == 0) 1419 { 1420 gbNotPrivateNoWarn = 1; 1421 } 1422 else if (strcasecmp(argv[i], "--with-tracing") == 0) 1423 { 1424 if (!pszStubFileName) 1425 { 1426 fprintf(stderr, "Error: cannot use --with-tracing without -s option.\n"); 1427 return -1; 1428 } 1429 gbTracing = 1; 1430 } 1431 else if (argv[i][1] == 'a' && argv[i][2] == '=') 1432 { 1433 pszArchString = argv[i] + 3; 1434 } 1435 else 1436 { 1437 fprintf(stderr, "Unrecognized option: %s\n", argv[i]); 1438 return -1; 1439 } 1440 } 1441 1442 if (strcasecmp(pszArchString, "i386") == 0) 1443 { 1444 giArch = ARCH_X86; 1445 gpszUnderscore = "_"; 1446 } 1447 else if (strcasecmp(pszArchString, "x86_64") == 0) giArch = ARCH_AMD64; 1448 else if (strcasecmp(pszArchString, "ia64") == 0) giArch = ARCH_IA64; 1449 else if (strcasecmp(pszArchString, "arm") == 0) giArch = ARCH_ARM; 1450 else if (strcasecmp(pszArchString, "ppc") == 0) giArch = ARCH_PPC; 1451 1452 if ((giArch == ARCH_AMD64) || (giArch == ARCH_IA64)) 1453 { 1454 pszArchString2 = "win64"; 1455 } 1456 else 1457 pszArchString2 = "win32"; 1458 1459 /* Set a default dll name */ 1460 if (!pszDllName) 1461 { 1462 char *p1, *p2; 1463 size_t len; 1464 1465 p1 = strrchr(argv[i], '\\'); 1466 if (!p1) p1 = strrchr(argv[i], '/'); 1467 p2 = p1 = p1 ? p1 + 1 : argv[i]; 1468 1469 /* walk up to '.' */ 1470 while (*p2 != '.' && *p2 != 0) p2++; 1471 len = p2 - p1; 1472 if (len >= sizeof(achDllName) - 5) 1473 { 1474 fprintf(stderr, "name too long: %s\n", p1); 1475 return -2; 1476 } 1477 1478 strncpy(achDllName, p1, len); 1479 strncpy(achDllName + len, ".dll", sizeof(achDllName) - len); 1480 pszDllName = achDllName; 1481 } 1482 1483 /* Open input file */ 1484 pszSourceFileName = argv[i]; 1485 file = fopen(pszSourceFileName, "r"); 1486 if (!file) 1487 { 1488 fprintf(stderr, "error: could not open file %s\n", pszSourceFileName); 1489 return -3; 1490 } 1491 1492 /* Get file size */ 1493 fseek(file, 0, SEEK_END); 1494 nFileSize = ftell(file); 1495 rewind(file); 1496 1497 /* Allocate memory buffer */ 1498 pszSource = malloc(nFileSize + 1); 1499 if (!pszSource) 1500 { 1501 fclose(file); 1502 return -4; 1503 } 1504 1505 /* Load input file into memory */ 1506 nFileSize = fread(pszSource, 1, nFileSize, file); 1507 fclose(file); 1508 1509 /* Zero terminate the source */ 1510 pszSource[nFileSize] = '\0'; 1511 1512 pexports = ParseFile(pszSource, file, &cExports); 1513 if (pexports == NULL) 1514 { 1515 fprintf(stderr, "error: could not parse file!\n"); 1516 return -1; 1517 } 1518 1519 if (!gbMSComp) 1520 { 1521 if (ApplyOrdinals(pexports, cExports) < 0) 1522 { 1523 fprintf(stderr, "error: could not apply ordinals!\n"); 1524 return -1; 1525 } 1526 } 1527 1528 if (pszDefFileName) 1529 { 1530 /* Open output file */ 1531 file = fopen(pszDefFileName, "w"); 1532 if (!file) 1533 { 1534 fprintf(stderr, "error: could not open output file %s\n", argv[i + 1]); 1535 return -5; 1536 } 1537 1538 OutputHeader_def(file, pszDllName); 1539 1540 for (i = 0; i < cExports; i++) 1541 { 1542 if (pexports[i].bVersionIncluded) 1543 OutputLine_def(file, &pexports[i]); 1544 } 1545 1546 fclose(file); 1547 } 1548 1549 if (pszStubFileName) 1550 { 1551 /* Open output file */ 1552 file = fopen(pszStubFileName, "w"); 1553 if (!file) 1554 { 1555 fprintf(stderr, "error: could not open output file %s\n", argv[i + 1]); 1556 return -5; 1557 } 1558 1559 OutputHeader_stub(file); 1560 1561 for (i = 0; i < cExports; i++) 1562 { 1563 if (pexports[i].bVersionIncluded) 1564 OutputLine_stub(file, &pexports[i]); 1565 } 1566 1567 fclose(file); 1568 } 1569 1570 if (pszLibStubName) 1571 { 1572 /* Open output file */ 1573 file = fopen(pszLibStubName, "w"); 1574 if (!file) 1575 { 1576 fprintf(stderr, "error: could not open output file %s\n", argv[i + 1]); 1577 return -5; 1578 } 1579 1580 OutputHeader_asmstub(file, pszDllName); 1581 1582 for (i = 0; i < cExports; i++) 1583 { 1584 if (pexports[i].bVersionIncluded) 1585 OutputLine_asmstub(file, &pexports[i]); 1586 } 1587 1588 fprintf(file, "\n END\n"); 1589 fclose(file); 1590 } 1591 1592 free(pexports); 1593 1594 return 0; 1595 } 1596