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