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