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 /* Don't add private exports to the import lib */ 734 if (gbImportLib && (pexp->uFlags & FL_PRIVATE)) 735 { 736 DbgPrint("OutputLine_def: skipping private export '%.*s'...\n", pexp->strName.len, pexp->strName.buf); 737 return 1; 738 } 739 740 DbgPrint("OutputLine_def: '%.*s'...\n", pexp->strName.len, pexp->strName.buf); 741 fprintf(fileDest, " "); 742 743 if (gbMSComp) 744 OutputLine_def_MS(fileDest, pexp); 745 else 746 OutputLine_def_GCC(fileDest, pexp); 747 748 /* On GCC builds we force ordinals */ 749 if ((pexp->uFlags & FL_ORDINAL) || (!gbMSComp && !gbImportLib)) 750 { 751 fprintf(fileDest, " @%d", pexp->nOrdinal); 752 } 753 754 if (pexp->uFlags & FL_NONAME) 755 { 756 fprintf(fileDest, " NONAME"); 757 } 758 759 /* Either PRIVATE or DATA */ 760 if (pexp->uFlags & FL_PRIVATE) 761 { 762 fprintf(fileDest, " PRIVATE"); 763 } 764 else if (pexp->nCallingConvention == CC_EXTERN) 765 { 766 fprintf(fileDest, " DATA"); 767 } 768 769 fprintf(fileDest, "\n"); 770 771 return 1; 772 } 773 774 void 775 Fatalv( 776 const char* filename, 777 unsigned nLine, 778 const char *pcLine, 779 const char *pc, 780 size_t errorlen, 781 const char *format, 782 va_list argptr) 783 { 784 unsigned i, errorpos, len; 785 const char* pcLineEnd; 786 787 /* Get the length of the line */ 788 pcLineEnd = strpbrk(pcLine, "\r\n"); 789 len = (unsigned)(pcLineEnd - pcLine); 790 791 if (pc == NULL) 792 { 793 pc = pcLine + len - 1; 794 errorlen = 1; 795 } 796 797 errorpos = (unsigned)(pc - pcLine); 798 799 /* Output the error message */ 800 fprintf(stderr, "ERROR: (%s:%u:%u): ", filename, nLine, errorpos); 801 vfprintf(stderr, format, argptr); 802 fprintf(stderr, "\n"); 803 804 /* Output the line with the error */ 805 fprintf(stderr, "> %.*s\n", len, pcLine); 806 807 if (errorlen == 0) 808 { 809 errorlen = TokenLength(pc); 810 } 811 812 for (i = 0; i < errorpos + 2; i++) 813 { 814 fprintf(stderr, " "); 815 } 816 for (i = 0; i < errorlen; i++) 817 { 818 fprintf(stderr, "~"); 819 } 820 fprintf(stderr, "\n"); 821 exit(-1); 822 } 823 824 void 825 Fatal( 826 const char* filename, 827 unsigned nLine, 828 const char *pcLine, 829 const char *pc, 830 size_t errorlen, 831 const char *format, 832 ...) 833 { 834 va_list argptr; 835 836 va_start(argptr, format); 837 Fatalv(filename, nLine, pcLine, pc, errorlen, format, argptr); 838 va_end(argptr); 839 } 840 841 EXPORT * 842 ParseFile(char* pcStart, FILE *fileDest, unsigned *cExports) 843 { 844 EXPORT *pexports; 845 const char *pc, *pcLine; 846 int cLines, nLine; 847 EXPORT exp; 848 int included; 849 unsigned int i; 850 851 *cExports = 0; 852 853 //fprintf(stderr, "info: line %d, pcStart:'%.30s'\n", nLine, pcStart); 854 855 /* Count the lines */ 856 for (cLines = 1, pcLine = pcStart; *pcLine; pcLine = NextLine(pcLine), cLines++) 857 { 858 /* Nothing */ 859 } 860 861 /* Allocate an array of EXPORT structures */ 862 pexports = malloc(cLines * sizeof(EXPORT)); 863 if (pexports == NULL) 864 { 865 fprintf(stderr, "ERROR: %s: failed to allocate EXPORT array of %u elements\n", pszSourceFileName, cLines); 866 return NULL; 867 } 868 869 /* Loop all lines */ 870 nLine = 1; 871 exp.nNumber = 0; 872 for (pcLine = pcStart; *pcLine; pcLine = NextLine(pcLine), nLine++) 873 { 874 pc = pcLine; 875 876 exp.strName.buf = NULL; 877 exp.strName.len = 0; 878 exp.strTarget.buf = NULL; 879 exp.strTarget.len = 0; 880 exp.nArgCount = 0; 881 exp.uFlags = 0; 882 exp.nNumber++; 883 exp.nStartVersion = 0; 884 exp.nEndVersion = 0xFFFFFFFF; 885 exp.bVersionIncluded = 1; 886 887 /* Skip white spaces */ 888 while (*pc == ' ' || *pc == '\t') pc++; 889 890 /* Check for line break or comment */ 891 if ((*pc == '\r') || (*pc == '\n') || 892 (*pc == ';') || (*pc == '#')) 893 { 894 continue; 895 } 896 897 /* On EOF we are done */ 898 if (*pc == 0) 899 { 900 return pexports; 901 } 902 903 /* Now we should get either an ordinal or @ */ 904 if (*pc == '@') 905 { 906 exp.nOrdinal = -1; 907 } 908 else if ((*pc >= '0') && (*pc <= '9')) 909 { 910 char* end; 911 long int number = strtol(pc, &end, 10); 912 if ((*end != ' ') && (*end != '\t')) 913 { 914 Fatal(pszSourceFileName, nLine, pcLine, end, 0, "Unexpected character(s) after ordinal"); 915 } 916 917 if ((number < 0) || (number > 0xFFFE)) 918 { 919 Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Invalid value for ordinal"); 920 } 921 922 exp.nOrdinal = number; 923 924 /* The import lib should contain the ordinal only if -ordinal was specified */ 925 if (!gbImportLib) 926 exp.uFlags |= FL_ORDINAL; 927 } 928 else 929 { 930 Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Expected '@' or ordinal"); 931 } 932 933 /* Go to next token (type) */ 934 if (!(pc = NextToken(pc))) 935 { 936 Fatal(pszSourceFileName, nLine, pcLine, pc, 1, "Unexpected end of line"); 937 } 938 939 //fprintf(stderr, "info: Token:'%.*s'\n", TokenLength(pc), pc); 940 941 /* Now we should get the type */ 942 if (CompareToken(pc, "stdcall")) 943 { 944 exp.nCallingConvention = CC_STDCALL; 945 } 946 else if (CompareToken(pc, "cdecl") || 947 CompareToken(pc, "varargs")) 948 { 949 exp.nCallingConvention = CC_CDECL; 950 } 951 else if (CompareToken(pc, "fastcall")) 952 { 953 exp.nCallingConvention = CC_FASTCALL; 954 } 955 else if (CompareToken(pc, "thiscall")) 956 { 957 exp.nCallingConvention = CC_THISCALL; 958 } 959 else if (CompareToken(pc, "extern")) 960 { 961 exp.nCallingConvention = CC_EXTERN; 962 } 963 else if (CompareToken(pc, "stub")) 964 { 965 exp.nCallingConvention = CC_STUB; 966 } 967 else 968 { 969 Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Invalid calling convention"); 970 } 971 972 /* Go to next token (options or name) */ 973 if (!(pc = NextToken(pc))) 974 { 975 Fatal(pszSourceFileName, nLine, pcLine, pc, 1, "Unexpected end of line"); 976 } 977 978 /* Handle options */ 979 included = 1; 980 while (*pc == '-') 981 { 982 if (CompareToken(pc, "-arch=")) 983 { 984 /* Default to not included */ 985 included = 0; 986 pc += 5; 987 988 /* Look if we are included */ 989 do 990 { 991 pc++; 992 if (CompareToken(pc, pszArchString) || 993 CompareToken(pc, pszArchString2)) 994 { 995 included = 1; 996 } 997 998 /* Skip to next arch or end */ 999 while (*pc > ',') pc++; 1000 } while (*pc == ','); 1001 } 1002 else if (CompareToken(pc, "-i386")) 1003 { 1004 if (giArch != ARCH_X86) included = 0; 1005 } 1006 else if (CompareToken(pc, "-version=")) 1007 { 1008 const char *pcVersionStart = pc + 9; 1009 1010 /* Default to not included */ 1011 exp.bVersionIncluded = 0; 1012 pc += 8; 1013 1014 /* Look if we are included */ 1015 do 1016 { 1017 unsigned version, endversion; 1018 1019 /* Optionally skip leading '0x' */ 1020 pc++; 1021 if ((pc[0] == '0') && (pc[1] == 'x')) pc += 2; 1022 1023 /* Now get the version number */ 1024 endversion = version = strtoul(pc, (char**)&pc, 16); 1025 1026 /* Check if it's a range */ 1027 if (pc[0] == '+') 1028 { 1029 endversion = 0xFFF; 1030 pc++; 1031 } 1032 else if (pc[0] == '-') 1033 { 1034 /* Optionally skip leading '0x' */ 1035 pc++; 1036 if ((pc[0] == '0') && (pc[1] == 'x')) pc += 2; 1037 endversion = strtoul(pc, (char**)&pc, 16); 1038 } 1039 1040 /* Check for degenerate range */ 1041 if (version > endversion) 1042 { 1043 Fatal(pszSourceFileName, 1044 nLine, 1045 pcLine, 1046 pcVersionStart, 1047 pc - pcVersionStart, 1048 "Invalid version range"); 1049 } 1050 1051 exp.nStartVersion = version; 1052 exp.nEndVersion = endversion; 1053 1054 /* Now compare the range with our version */ 1055 if ((guOsVersion >= version) && 1056 (guOsVersion <= endversion)) 1057 { 1058 exp.bVersionIncluded = 1; 1059 } 1060 1061 /* Skip to next arch or end */ 1062 while (*pc > ',') pc++; 1063 1064 } while (*pc == ','); 1065 } 1066 else if (CompareToken(pc, "-private")) 1067 { 1068 exp.uFlags |= FL_PRIVATE; 1069 } 1070 else if (CompareToken(pc, "-noname")) 1071 { 1072 exp.uFlags |= FL_ORDINAL | FL_NONAME; 1073 } 1074 else if (CompareToken(pc, "-ordinal")) 1075 { 1076 exp.uFlags |= FL_ORDINAL; 1077 /* GCC doesn't automatically import by ordinal if an ordinal 1078 * is found in the def file. Force it. */ 1079 if (gbImportLib && !gbMSComp) 1080 exp.uFlags |= FL_NONAME; 1081 } 1082 else if (CompareToken(pc, "-stub")) 1083 { 1084 exp.uFlags |= FL_STUB; 1085 } 1086 else if (CompareToken(pc, "-norelay")) 1087 { 1088 exp.uFlags |= FL_NORELAY; 1089 } 1090 else if (CompareToken(pc, "-ret64")) 1091 { 1092 exp.uFlags |= FL_RET64; 1093 } 1094 else if (CompareToken(pc, "-register")) 1095 { 1096 exp.uFlags |= FL_REGISTER; 1097 } 1098 else 1099 { 1100 fprintf(stdout, 1101 "INFO: %s line %d: Ignored option: '%.*s'\n", 1102 pszSourceFileName, 1103 nLine, 1104 TokenLength(pc), 1105 pc); 1106 } 1107 1108 /* Go to next token */ 1109 pc = NextToken(pc); 1110 } 1111 1112 //fprintf(stderr, "info: Name:'%.10s'\n", pc); 1113 1114 /* If arch didn't match ours, skip this entry */ 1115 if (!included) continue; 1116 1117 /* Get name */ 1118 exp.strName.buf = pc; 1119 exp.strName.len = TokenLength(pc); 1120 //DbgPrint("Got name: '%.*s'\n", exp.strName.len, exp.strName.buf); 1121 1122 /* Check for autoname */ 1123 if ((exp.strName.len == 1) && (exp.strName.buf[0] == '@')) 1124 { 1125 exp.uFlags |= FL_ORDINAL | FL_NONAME; 1126 } 1127 1128 /* Handle parameters */ 1129 exp.nStackBytes = 0; 1130 if (exp.nCallingConvention != CC_EXTERN && 1131 exp.nCallingConvention != CC_STUB) 1132 { 1133 /* Go to next token */ 1134 if (!(pc = NextToken(pc))) 1135 { 1136 Fatal(pszSourceFileName, nLine, pcLine, pc, 1, "Unexpected end of line"); 1137 } 1138 1139 /* Verify syntax */ 1140 if (*pc++ != '(') 1141 { 1142 Fatal(pszSourceFileName, nLine, pcLine, pc - 1, 0, "Expected '('"); 1143 } 1144 1145 /* Skip whitespaces */ 1146 while (*pc == ' ' || *pc == '\t') pc++; 1147 1148 exp.nStackBytes = 0; 1149 while (*pc >= '0') 1150 { 1151 if (CompareToken(pc, "long")) 1152 { 1153 exp.nStackBytes += 4; 1154 exp.anArgs[exp.nArgCount] = ARG_LONG; 1155 } 1156 else if (CompareToken(pc, "double")) 1157 { 1158 exp.nStackBytes += 8; 1159 exp.anArgs[exp.nArgCount] = ARG_DBL; 1160 } 1161 else if (CompareToken(pc, "ptr")) 1162 { 1163 exp.nStackBytes += 4; // sizeof(void*) on x86 1164 exp.anArgs[exp.nArgCount] = ARG_PTR; 1165 } 1166 else if (CompareToken(pc, "str")) 1167 { 1168 exp.nStackBytes += 4; // sizeof(void*) on x86 1169 exp.anArgs[exp.nArgCount] = ARG_STR; 1170 } 1171 else if (CompareToken(pc, "wstr")) 1172 { 1173 exp.nStackBytes += 4; // sizeof(void*) on x86 1174 exp.anArgs[exp.nArgCount] = ARG_WSTR; 1175 } 1176 else if (CompareToken(pc, "int64")) 1177 { 1178 exp.nStackBytes += 8; 1179 exp.anArgs[exp.nArgCount] = ARG_INT64; 1180 } 1181 else if (CompareToken(pc, "int128")) 1182 { 1183 exp.nStackBytes += 16; 1184 exp.anArgs[exp.nArgCount] = ARG_INT128; 1185 } 1186 else if (CompareToken(pc, "float")) 1187 { 1188 exp.nStackBytes += 4; 1189 exp.anArgs[exp.nArgCount] = ARG_FLOAT; 1190 } 1191 else 1192 { 1193 Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Unrecognized type"); 1194 } 1195 1196 exp.nArgCount++; 1197 1198 /* Go to next parameter */ 1199 if (!(pc = NextToken(pc))) 1200 { 1201 Fatal(pszSourceFileName, nLine, pcLine, pc, 1, "Unexpected end of line"); 1202 } 1203 } 1204 1205 /* Check syntax */ 1206 if (*pc++ != ')') 1207 { 1208 Fatal(pszSourceFileName, nLine, pcLine, pc - 1, 0, "Expected ')'"); 1209 } 1210 } 1211 1212 /* Handle special stub cases */ 1213 if (exp.nCallingConvention == CC_STUB) 1214 { 1215 /* Check for c++ mangled name */ 1216 if (pc[0] == '?') 1217 { 1218 //printf("Found c++ mangled name...\n"); 1219 // 1220 } 1221 else 1222 { 1223 /* Check for stdcall name */ 1224 const char *p = ScanToken(pc, '@'); 1225 if (p && (p - pc < exp.strName.len)) 1226 { 1227 int i; 1228 1229 /* Truncate the name to before the @ */ 1230 exp.strName.len = (int)(p - pc); 1231 if (exp.strName.len < 1) 1232 { 1233 Fatal(pszSourceFileName, nLine, pcLine, p, 1, "Unexpected @"); 1234 } 1235 exp.nStackBytes = atoi(p + 1); 1236 exp.nArgCount = exp.nStackBytes / 4; 1237 exp.nCallingConvention = CC_STDCALL; 1238 exp.uFlags |= FL_STUB; 1239 for (i = 0; i < exp.nArgCount; i++) 1240 exp.anArgs[i] = ARG_LONG; 1241 } 1242 } 1243 } 1244 1245 /* Get optional redirection */ 1246 pc = NextToken(pc); 1247 if (pc) 1248 { 1249 exp.strTarget.buf = pc; 1250 exp.strTarget.len = TokenLength(pc); 1251 1252 /* Check syntax (end of line) */ 1253 if (NextToken(pc)) 1254 { 1255 Fatal(pszSourceFileName, nLine, pcLine, NextToken(pc), 0, "Excess token(s) at end of definition"); 1256 } 1257 1258 /* Don't relay-trace forwarded functions */ 1259 exp.uFlags |= FL_NORELAY; 1260 } 1261 else 1262 { 1263 exp.strTarget.buf = NULL; 1264 exp.strTarget.len = 0; 1265 } 1266 1267 /* Check for no-name without ordinal */ 1268 if ((exp.uFlags & FL_ORDINAL) && (exp.nOrdinal == -1)) 1269 { 1270 Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Ordinal export without ordinal"); 1271 } 1272 1273 /* 1274 * Check for special handling of OLE exports, only when MSVC 1275 * is not used, since otherwise this is handled by MS LINK.EXE. 1276 */ 1277 if (!gbMSComp) 1278 { 1279 /* Check whether the current export is not PRIVATE, or has an ordinal */ 1280 int bIsNotPrivate = (!gbNotPrivateNoWarn && /*gbImportLib &&*/ !(exp.uFlags & FL_PRIVATE)); 1281 int bHasOrdinal = (exp.uFlags & FL_ORDINAL); 1282 1283 /* Check whether the current export is an OLE export, in case any of these tests pass */ 1284 if (bIsNotPrivate || bHasOrdinal) 1285 { 1286 for (i = 0; i < ARRAYSIZE(astrOlePrivateExports); ++i) 1287 { 1288 if (strlen(astrOlePrivateExports[i]) == exp.strName.len && 1289 strncmp(exp.strName.buf, astrOlePrivateExports[i], exp.strName.len) == 0) 1290 { 1291 /* The current export is an OLE export: display the corresponding warning */ 1292 if (bIsNotPrivate) 1293 { 1294 fprintf(stderr, "WARNING: %s line %d: Exported symbol '%.*s' should be PRIVATE\n", 1295 pszSourceFileName, nLine, exp.strName.len, exp.strName.buf); 1296 } 1297 if (bHasOrdinal) 1298 { 1299 fprintf(stderr, "WARNING: %s line %d: exported symbol '%.*s' should not be assigned an ordinal\n", 1300 pszSourceFileName, nLine, exp.strName.len, exp.strName.buf); 1301 } 1302 break; 1303 } 1304 } 1305 } 1306 } 1307 1308 pexports[*cExports] = exp; 1309 (*cExports)++; 1310 gbDebug = 0; 1311 } 1312 1313 return pexports; 1314 } 1315 1316 int 1317 ApplyOrdinals(EXPORT* pexports, unsigned cExports) 1318 { 1319 unsigned short i, j; 1320 char* used; 1321 1322 /* Allocate a table to mark used ordinals */ 1323 used = malloc(65536); 1324 if (used == NULL) 1325 { 1326 fprintf(stderr, "Failed to allocate memory for ordinal use table\n"); 1327 return -1; 1328 } 1329 memset(used, 0, 65536); 1330 1331 /* Pass 1: mark the ordinals that are already used */ 1332 for (i = 0; i < cExports; i++) 1333 { 1334 if (pexports[i].uFlags & FL_ORDINAL) 1335 { 1336 if (used[pexports[i].nOrdinal] != 0) 1337 { 1338 fprintf(stderr, "Found duplicate ordinal: %u\n", pexports[i].nOrdinal); 1339 return -1; 1340 } 1341 used[pexports[i].nOrdinal] = 1; 1342 } 1343 } 1344 1345 /* Pass 2: apply available ordinals */ 1346 for (i = 0, j = 1; i < cExports; i++) 1347 { 1348 if ((pexports[i].uFlags & FL_ORDINAL) == 0 && pexports[i].bVersionIncluded) 1349 { 1350 while (used[j] != 0) 1351 j++; 1352 1353 pexports[i].nOrdinal = j; 1354 used[j] = 1; 1355 } 1356 } 1357 1358 free(used); 1359 return 0; 1360 } 1361 1362 void usage(void) 1363 { 1364 printf("syntax: spec2def [<options> ...] <spec file>\n" 1365 "Possible options:\n" 1366 " -h --help print this help screen\n" 1367 " -l=<file> generate an asm lib stub\n" 1368 " -d=<file> generate a def file\n" 1369 " -s=<file> generate a stub file\n" 1370 " --ms MSVC compatibility\n" 1371 " -n=<name> name of the dll\n" 1372 " --implib generate a def file for an import library\n" 1373 " --no-private-warnings suppress warnings about symbols that should be -private\n" 1374 " -a=<arch> set architecture to <arch> (i386, x86_64, arm)\n" 1375 " --with-tracing generate wine-like \"+relay\" trace trampolines (needs -s)\n"); 1376 } 1377 1378 int main(int argc, char *argv[]) 1379 { 1380 size_t nFileSize; 1381 char *pszSource, *pszDefFileName = NULL, *pszStubFileName = NULL, *pszLibStubName = NULL; 1382 const char* pszVersionOption = "--version=0x"; 1383 char achDllName[40]; 1384 FILE *file; 1385 unsigned cExports = 0, i; 1386 EXPORT *pexports; 1387 1388 if (argc < 2) 1389 { 1390 usage(); 1391 return -1; 1392 } 1393 1394 /* Read options */ 1395 for (i = 1; i < (unsigned)argc && *argv[i] == '-'; i++) 1396 { 1397 if ((strcasecmp(argv[i], "--help") == 0) || 1398 (strcasecmp(argv[i], "-h") == 0)) 1399 { 1400 usage(); 1401 return 0; 1402 } 1403 else if (argv[i][1] == 'd' && argv[i][2] == '=') 1404 { 1405 pszDefFileName = argv[i] + 3; 1406 } 1407 else if (argv[i][1] == 'l' && argv[i][2] == '=') 1408 { 1409 pszLibStubName = argv[i] + 3; 1410 } 1411 else if (argv[i][1] == 's' && argv[i][2] == '=') 1412 { 1413 pszStubFileName = argv[i] + 3; 1414 } 1415 else if (argv[i][1] == 'n' && argv[i][2] == '=') 1416 { 1417 pszDllName = argv[i] + 3; 1418 } 1419 else if (strncasecmp(argv[i], pszVersionOption, strlen(pszVersionOption)) == 0) 1420 { 1421 guOsVersion = strtoul(argv[i] + strlen(pszVersionOption), NULL, 16); 1422 } 1423 else if (strcasecmp(argv[i], "--implib") == 0) 1424 { 1425 gbImportLib = 1; 1426 } 1427 else if (strcasecmp(argv[i], "--ms") == 0) 1428 { 1429 gbMSComp = 1; 1430 } 1431 else if (strcasecmp(argv[i], "--no-private-warnings") == 0) 1432 { 1433 gbNotPrivateNoWarn = 1; 1434 } 1435 else if (strcasecmp(argv[i], "--with-tracing") == 0) 1436 { 1437 if (!pszStubFileName) 1438 { 1439 fprintf(stderr, "Error: cannot use --with-tracing without -s option.\n"); 1440 return -1; 1441 } 1442 gbTracing = 1; 1443 } 1444 else if (argv[i][1] == 'a' && argv[i][2] == '=') 1445 { 1446 pszArchString = argv[i] + 3; 1447 } 1448 else 1449 { 1450 fprintf(stderr, "Unrecognized option: %s\n", argv[i]); 1451 return -1; 1452 } 1453 } 1454 1455 if (strcasecmp(pszArchString, "i386") == 0) 1456 { 1457 giArch = ARCH_X86; 1458 gpszUnderscore = "_"; 1459 } 1460 else if (strcasecmp(pszArchString, "x86_64") == 0) giArch = ARCH_AMD64; 1461 else if (strcasecmp(pszArchString, "ia64") == 0) giArch = ARCH_IA64; 1462 else if (strcasecmp(pszArchString, "arm") == 0) giArch = ARCH_ARM; 1463 else if (strcasecmp(pszArchString, "ppc") == 0) giArch = ARCH_PPC; 1464 1465 if ((giArch == ARCH_AMD64) || (giArch == ARCH_IA64)) 1466 { 1467 pszArchString2 = "win64"; 1468 } 1469 else 1470 pszArchString2 = "win32"; 1471 1472 /* Set a default dll name */ 1473 if (!pszDllName) 1474 { 1475 char *p1, *p2; 1476 size_t len; 1477 1478 p1 = strrchr(argv[i], '\\'); 1479 if (!p1) p1 = strrchr(argv[i], '/'); 1480 p2 = p1 = p1 ? p1 + 1 : argv[i]; 1481 1482 /* walk up to '.' */ 1483 while (*p2 != '.' && *p2 != 0) p2++; 1484 len = p2 - p1; 1485 if (len >= sizeof(achDllName) - 5) 1486 { 1487 fprintf(stderr, "name too long: %s\n", p1); 1488 return -2; 1489 } 1490 1491 strncpy(achDllName, p1, len); 1492 strncpy(achDllName + len, ".dll", sizeof(achDllName) - len); 1493 pszDllName = achDllName; 1494 } 1495 1496 /* Open input file */ 1497 pszSourceFileName = argv[i]; 1498 file = fopen(pszSourceFileName, "r"); 1499 if (!file) 1500 { 1501 fprintf(stderr, "error: could not open file %s\n", pszSourceFileName); 1502 return -3; 1503 } 1504 1505 /* Get file size */ 1506 fseek(file, 0, SEEK_END); 1507 nFileSize = ftell(file); 1508 rewind(file); 1509 1510 /* Allocate memory buffer */ 1511 pszSource = malloc(nFileSize + 1); 1512 if (!pszSource) 1513 { 1514 fclose(file); 1515 return -4; 1516 } 1517 1518 /* Load input file into memory */ 1519 nFileSize = fread(pszSource, 1, nFileSize, file); 1520 fclose(file); 1521 1522 /* Zero terminate the source */ 1523 pszSource[nFileSize] = '\0'; 1524 1525 pexports = ParseFile(pszSource, file, &cExports); 1526 if (pexports == NULL) 1527 { 1528 fprintf(stderr, "error: could not parse file!\n"); 1529 return -1; 1530 } 1531 1532 if (!gbMSComp) 1533 { 1534 if (ApplyOrdinals(pexports, cExports) < 0) 1535 { 1536 fprintf(stderr, "error: could not apply ordinals!\n"); 1537 return -1; 1538 } 1539 } 1540 1541 if (pszDefFileName) 1542 { 1543 /* Open output file */ 1544 file = fopen(pszDefFileName, "w"); 1545 if (!file) 1546 { 1547 fprintf(stderr, "error: could not open output file %s\n", argv[i + 1]); 1548 return -5; 1549 } 1550 1551 OutputHeader_def(file, pszDllName); 1552 1553 for (i = 0; i < cExports; i++) 1554 { 1555 if (pexports[i].bVersionIncluded) 1556 OutputLine_def(file, &pexports[i]); 1557 } 1558 1559 fclose(file); 1560 } 1561 1562 if (pszStubFileName) 1563 { 1564 /* Open output file */ 1565 file = fopen(pszStubFileName, "w"); 1566 if (!file) 1567 { 1568 fprintf(stderr, "error: could not open output file %s\n", argv[i + 1]); 1569 return -5; 1570 } 1571 1572 OutputHeader_stub(file); 1573 1574 for (i = 0; i < cExports; i++) 1575 { 1576 if (pexports[i].bVersionIncluded) 1577 OutputLine_stub(file, &pexports[i]); 1578 } 1579 1580 fclose(file); 1581 } 1582 1583 if (pszLibStubName) 1584 { 1585 /* Open output file */ 1586 file = fopen(pszLibStubName, "w"); 1587 if (!file) 1588 { 1589 fprintf(stderr, "error: could not open output file %s\n", argv[i + 1]); 1590 return -5; 1591 } 1592 1593 OutputHeader_asmstub(file, pszDllName); 1594 1595 for (i = 0; i < cExports; i++) 1596 { 1597 if (pexports[i].bVersionIncluded) 1598 OutputLine_asmstub(file, &pexports[i]); 1599 } 1600 1601 fprintf(file, "\n END\n"); 1602 fclose(file); 1603 } 1604 1605 free(pexports); 1606 1607 return 0; 1608 } 1609