f5a91aa32615c294091d7a1409e663552e591c82
7 #define strcasecmp _stricmp
10 #define ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0]))
12 typedef struct _STRING
22 int nCallingConvention
;
40 typedef int (*PFNOUTLINE
)(FILE *, EXPORT
*);
43 int gbNotPrivateNoWarn
= 0;
45 int giArch
= ARCH_X86
;
46 char *pszArchString
= "i386";
48 char *pszSourceFileName
= NULL
;
49 char *pszDllName
= NULL
;
50 char *gpszUnderscore
= "";
52 unsigned guOsVersion
= 0x502;
53 #define DbgPrint(...) (!gbDebug || fprintf(stderr, __VA_ARGS__))
88 const char* astrCallingConventions
[] =
97 static const char* astrShouldBePrivate
[] =
101 "DllGetClassFactoryFromClassString",
102 "DllGetDocumentation",
106 "DllRegisterServerEx",
107 "DllRegisterServerExW",
109 "DllUnregisterServer",
110 "RasCustomDeleteEntryNotify",
118 IsSeparator(char chr
)
120 return ((chr
<= ',' && chr
!= '$' && chr
!= '#') ||
121 (chr
>= ':' && chr
< '?') );
125 CompareToken(const char *token
, const char *comparand
)
129 if (*token
!= *comparand
) return 0;
133 if (IsSeparator(comparand
[-1])) return 1;
134 if (!IsSeparator(*token
)) return 0;
139 ScanToken(const char *token
, char chr
)
141 while (!IsSeparator(*token
))
143 if (*token
== chr
) return token
;
154 if (pc
[0] == '\n' && pc
[1] == '\r') return pc
+ 2;
155 else if (pc
[0] == '\n') return pc
+ 1;
162 TokenLength(char *pc
)
166 while (!IsSeparator(*pc
++)) length
++;
175 while (!IsSeparator(*pc
)) pc
++;
177 /* Skip white spaces */
178 while (*pc
== ' ' || *pc
== '\t') pc
++;
180 /* Check for end of line */
181 if (*pc
== '\n' || *pc
== '\r' || *pc
== 0) return 0;
183 /* Check for comment */
184 if (*pc
== '#' || *pc
== ';') return 0;
190 OutputHeader_stub(FILE *file
)
192 fprintf(file
, "/* This file is autogenerated, do not edit. */\n\n"
193 "#include <stubs.h>\n");
197 fprintf(file
, "#include <wine/debug.h>\n");
198 fprintf(file
, "#include <inttypes.h>\n");
199 fprintf(file
, "WINE_DECLARE_DEBUG_CHANNEL(relay);\n");
206 OutputLine_stub(FILE *file
, EXPORT
*pexp
)
210 int bInPrototype
= 0;
212 if (pexp
->nCallingConvention
!= CC_STUB
&&
213 (pexp
->uFlags
& FL_STUB
) == 0)
215 /* Only relay trace stdcall C functions */
216 if (!gbTracing
|| (pexp
->nCallingConvention
!= CC_STDCALL
)
217 || (pexp
->uFlags
& FL_NORELAY
)
218 || (pexp
->strName
.buf
[0] == '?'))
225 /* Declare the "real" function */
228 fprintf(file
, "extern ");
234 if (pexp
->uFlags
& FL_REGISTER
)
236 /* FIXME: Not sure this is right */
237 fprintf(file
, "void ");
239 else if (pexp
->uFlags
& FL_RET64
)
241 fprintf(file
, "__int64 ");
245 fprintf(file
, "int ");
248 if ((giArch
== ARCH_X86
) &&
249 pexp
->nCallingConvention
== CC_STDCALL
)
251 fprintf(file
, "__stdcall ");
255 if (pexp
->strName
.buf
[0] == '?')
257 fprintf(file
, "stub_function%d(", pexp
->nNumber
);
261 if (!bRelay
|| bInPrototype
)
262 fprintf(file
, "%.*s(", pexp
->strName
.len
, pexp
->strName
.buf
);
264 fprintf(file
, "$relaytrace$%.*s(", pexp
->strName
.len
, pexp
->strName
.buf
);
267 for (i
= 0; i
< pexp
->nArgCount
; i
++)
269 if (i
!= 0) fprintf(file
, ", ");
270 switch (pexp
->anArgs
[i
])
272 case ARG_LONG
: fprintf(file
, "long"); break;
273 case ARG_PTR
: fprintf(file
, "void*"); break;
274 case ARG_STR
: fprintf(file
, "char*"); break;
275 case ARG_WSTR
: fprintf(file
, "wchar_t*"); break;
276 case ARG_DBL
: fprintf(file
, "double"); break;
277 case ARG_INT64
: fprintf(file
, "__int64"); break;
278 /* __int128 is not supported on x86, and int128 in spec files most often represents a GUID */
279 case ARG_INT128
: fprintf(file
, "GUID"); break;
280 case ARG_FLOAT
: fprintf(file
, "float"); break;
282 fprintf(file
, " a%d", i
);
287 fprintf(file
, ");\n\n");
289 } while (bInPrototype
--);
293 fprintf(file
, ")\n{\n\tDbgPrint(\"WARNING: calling stub %.*s(",
294 pexp
->strName
.len
, pexp
->strName
.buf
);
298 fprintf(file
, ")\n{\n");
299 if (pexp
->uFlags
& FL_REGISTER
)
301 /* No return value */
303 else if (pexp
->uFlags
& FL_RET64
)
305 fprintf(file
, "\t__int64 retval;\n");
309 fprintf(file
, "\tint retval;\n");
311 fprintf(file
, "\tif (TRACE_ON(relay))\n\t\tDPRINTF(\"%s: %.*s(",
312 pszDllName
, pexp
->strName
.len
, pexp
->strName
.buf
);
315 for (i
= 0; i
< pexp
->nArgCount
; i
++)
317 if (i
!= 0) fprintf(file
, ",");
318 switch (pexp
->anArgs
[i
])
320 case ARG_LONG
: fprintf(file
, "0x%%lx"); break;
321 case ARG_PTR
: fprintf(file
, "0x%%p"); break;
322 case ARG_STR
: fprintf(file
, "'%%s'"); break;
323 case ARG_WSTR
: fprintf(file
, "'%%ws'"); break;
324 case ARG_DBL
: fprintf(file
, "%%f"); break;
325 case ARG_INT64
: fprintf(file
, "%%\"PRIx64\""); break;
326 case ARG_INT128
: fprintf(file
, "'%%s'"); break;
327 case ARG_FLOAT
: fprintf(file
, "%%f"); break;
330 fprintf(file
, ")\\n\"");
332 for (i
= 0; i
< pexp
->nArgCount
; i
++)
335 switch (pexp
->anArgs
[i
])
337 case ARG_LONG
: fprintf(file
, "(long)a%d", i
); break;
338 case ARG_PTR
: fprintf(file
, "(void*)a%d", i
); break;
339 case ARG_STR
: fprintf(file
, "(char*)a%d", i
); break;
340 case ARG_WSTR
: fprintf(file
, "(wchar_t*)a%d", i
); break;
341 case ARG_DBL
: fprintf(file
, "(double)a%d", i
); break;
342 case ARG_INT64
: fprintf(file
, "(__int64)a%d", i
); break;
343 case ARG_INT128
: fprintf(file
, "wine_dbgstr_guid(&a%d)", i
); break;
344 case ARG_FLOAT
: fprintf(file
, "(float)a%d", i
); break;
347 fprintf(file
, ");\n");
349 if (pexp
->nCallingConvention
== CC_STUB
)
351 fprintf(file
, "\t__wine_spec_unimplemented_stub(\"%s\", __FUNCTION__);\n", pszDllName
);
355 if (pexp
->uFlags
& FL_REGISTER
)
361 fprintf(file
, "\tretval = ");
363 fprintf(file
, "%.*s(", pexp
->strName
.len
, pexp
->strName
.buf
);
365 for (i
= 0; i
< pexp
->nArgCount
; i
++)
367 if (i
!= 0) fprintf(file
, ", ");
368 fprintf(file
, "a%d", i
);
370 fprintf(file
, ");\n");
374 fprintf(file
, "\treturn 0;\n}\n\n");
375 else if ((pexp
->uFlags
& FL_REGISTER
) == 0)
377 if (pexp
->uFlags
& FL_RET64
)
379 fprintf(file
, "\tif (TRACE_ON(relay))\n\t\tDPRINTF(\"%s: %.*s: retval = %%\"PRIx64\"\\n\", retval);\n",
380 pszDllName
, pexp
->strName
.len
, pexp
->strName
.buf
);
384 fprintf(file
, "\tif (TRACE_ON(relay))\n\t\tDPRINTF(\"%s: %.*s: retval = 0x%%lx\\n\", retval);\n",
385 pszDllName
, pexp
->strName
.len
, pexp
->strName
.buf
);
387 fprintf(file
, "\treturn retval;\n}\n\n");
394 OutputHeader_asmstub(FILE *file
, char *libname
)
396 fprintf(file
, "; File generated automatically, do not edit! \n\n");
398 if (giArch
== ARCH_X86
)
400 fprintf(file
, ".586\n.model flat\n.code\n");
402 else if (giArch
== ARCH_AMD64
)
404 fprintf(file
, ".code\n");
406 else if (giArch
== ARCH_ARM
)
408 fprintf(file
, " AREA |.text|,ALIGN=2,CODE,READONLY\n\n");
413 Output_stublabel(FILE *fileDest
, char* pszSymbolName
)
415 if (giArch
== ARCH_ARM
)
418 "\tEXPORT |%s| [FUNC]\n|%s|\n",
425 "PUBLIC %s\n%s: nop\n",
432 OutputLine_asmstub(FILE *fileDest
, EXPORT
*pexp
)
434 char szNameBuffer
[128];
436 /* Handle autoname */
437 if (pexp
->strName
.len
== 1 && pexp
->strName
.buf
[0] == '@')
439 sprintf(szNameBuffer
, "%sordinal%d\n%sordinal%d: nop\n",
440 gpszUnderscore
, pexp
->nOrdinal
, gpszUnderscore
, pexp
->nOrdinal
);
442 else if (giArch
!= ARCH_X86
)
444 sprintf(szNameBuffer
, "_stub_%.*s",
445 pexp
->strName
.len
, pexp
->strName
.buf
);
447 else if (pexp
->nCallingConvention
== CC_STDCALL
)
449 sprintf(szNameBuffer
, "__stub_%.*s@%d",
450 pexp
->strName
.len
, pexp
->strName
.buf
, pexp
->nStackBytes
);
452 else if (pexp
->nCallingConvention
== CC_FASTCALL
)
454 sprintf(szNameBuffer
, "@_stub_%.*s@%d",
455 pexp
->strName
.len
, pexp
->strName
.buf
, pexp
->nStackBytes
);
457 else if ((pexp
->nCallingConvention
== CC_CDECL
) ||
458 (pexp
->nCallingConvention
== CC_THISCALL
) ||
459 (pexp
->nCallingConvention
== CC_EXTERN
) ||
460 (pexp
->nCallingConvention
== CC_STUB
))
462 sprintf(szNameBuffer
, "__stub_%.*s",
463 pexp
->strName
.len
, pexp
->strName
.buf
);
467 fprintf(stderr
, "Invalid calling convention");
471 Output_stublabel(fileDest
, szNameBuffer
);
477 OutputHeader_def(FILE *file
, char *libname
)
480 "; File generated automatically, do not edit!\n\n"
487 PrintName(FILE *fileDest
, EXPORT
*pexp
, PSTRING pstr
, int fDeco
)
489 const char *pcName
= pstr
->buf
;
490 int nNameLength
= pstr
->len
;
491 const char* pcDot
, *pcAt
;
493 /* Check for non-x86 first */
494 if (giArch
!= ARCH_X86
)
496 /* Does the string already have stdcall decoration? */
497 pcAt
= ScanToken(pcName
, '@');
498 if (pcAt
&& (pcAt
< (pcName
+ nNameLength
)) && (pcName
[0] == '_'))
500 /* Skip leading underscore and remove trailing decoration */
502 nNameLength
= pcAt
- pcName
;
505 /* Print the undecorated function name */
506 fprintf(fileDest
, "%.*s", nNameLength
, pcName
);
509 ((pexp
->nCallingConvention
== CC_STDCALL
) ||
510 (pexp
->nCallingConvention
== CC_FASTCALL
)))
512 /* Scan for a dll forwarding dot */
513 pcDot
= ScanToken(pcName
, '.');
516 /* First print the dll name, followed by a dot */
517 nNameLength
= pcDot
- pcName
;
518 fprintf(fileDest
, "%.*s.", nNameLength
, pcName
);
520 /* Now the actual function name */
522 nNameLength
= pexp
->strTarget
.len
- nNameLength
- 1;
525 /* Does the string already have decoration? */
526 pcAt
= ScanToken(pcName
, '@');
527 if (pcAt
&& (pcAt
< (pcName
+ nNameLength
)))
529 /* On GCC, we need to remove the leading stdcall underscore */
530 if (!gbMSComp
&& (pexp
->nCallingConvention
== CC_STDCALL
))
536 /* Print the already decorated function name */
537 fprintf(fileDest
, "%.*s", nNameLength
, pcName
);
541 /* Print the prefix, but skip it for (GCC && stdcall) */
542 if (gbMSComp
|| (pexp
->nCallingConvention
!= CC_STDCALL
))
544 fprintf(fileDest
, "%c", pexp
->nCallingConvention
== CC_FASTCALL
? '@' : '_');
547 /* Print the name with trailing decoration */
548 fprintf(fileDest
, "%.*s@%d", nNameLength
, pcName
, pexp
->nStackBytes
);
553 /* Print the undecorated function name */
554 fprintf(fileDest
, "%.*s", nNameLength
, pcName
);
559 OutputLine_def_MS(FILE *fileDest
, EXPORT
*pexp
)
561 PrintName(fileDest
, pexp
, &pexp
->strName
, 0);
565 /* Redirect to a stub function, to get the right decoration in the lib */
566 fprintf(fileDest
, "=_stub_%.*s", pexp
->strName
.len
, pexp
->strName
.buf
);
568 else if (pexp
->strTarget
.buf
)
570 if (pexp
->strName
.buf
[0] == '?')
572 //fprintf(stderr, "warning: ignoring C++ redirection %.*s -> %.*s\n",
573 // pexp->strName.len, pexp->strName.buf, pexp->strTarget.len, pexp->strTarget.buf);
577 fprintf(fileDest
, "=");
579 /* If the original name was decorated, use decoration in the forwarder as well */
580 if ((giArch
== ARCH_X86
) && ScanToken(pexp
->strName
.buf
, '@') &&
581 !ScanToken(pexp
->strTarget
.buf
, '@') &&
582 ((pexp
->nCallingConvention
== CC_STDCALL
) ||
583 (pexp
->nCallingConvention
== CC_FASTCALL
)) )
585 PrintName(fileDest
, pexp
, &pexp
->strTarget
, 1);
589 /* Write the undecorated redirection name */
590 fprintf(fileDest
, "%.*s", pexp
->strTarget
.len
, pexp
->strTarget
.buf
);
594 else if (((pexp
->uFlags
& FL_STUB
) || (pexp
->nCallingConvention
== CC_STUB
)) &&
595 (pexp
->strName
.buf
[0] == '?'))
597 /* C++ stubs are forwarded to C stubs */
598 fprintf(fileDest
, "=stub_function%d", pexp
->nNumber
);
600 else if (gbTracing
&& ((pexp
->uFlags
& FL_NORELAY
) == 0) && (pexp
->nCallingConvention
== CC_STDCALL
) &&
601 (pexp
->strName
.buf
[0] != '?'))
603 /* Redirect it to the relay-tracing trampoline */
604 fprintf(fileDest
, "=$relaytrace$%.*s", pexp
->strName
.len
, pexp
->strName
.buf
);
609 OutputLine_def_GCC(FILE *fileDest
, EXPORT
*pexp
)
612 /* Print the function name, with decoration for export libs */
613 PrintName(fileDest
, pexp
, &pexp
->strName
, gbImportLib
);
614 DbgPrint("Generating def line for '%.*s'\n", pexp
->strName
.len
, pexp
->strName
.buf
);
616 /* Check if this is a forwarded export */
617 if (pexp
->strTarget
.buf
)
619 int fIsExternal
= !!ScanToken(pexp
->strTarget
.buf
, '.');
620 DbgPrint("Got redirect '%.*s'\n", pexp
->strTarget
.len
, pexp
->strTarget
.buf
);
622 /* print the target name, don't decorate if it is external */
623 fprintf(fileDest
, "=");
624 PrintName(fileDest
, pexp
, &pexp
->strTarget
, !fIsExternal
);
626 else if (((pexp
->uFlags
& FL_STUB
) || (pexp
->nCallingConvention
== CC_STUB
)) &&
627 (pexp
->strName
.buf
[0] == '?'))
629 /* C++ stubs are forwarded to C stubs */
630 fprintf(fileDest
, "=stub_function%d", pexp
->nNumber
);
632 else if (gbTracing
&& ((pexp
->uFlags
& FL_NORELAY
) == 0) &&
633 (pexp
->nCallingConvention
== CC_STDCALL
) &&
634 (pexp
->strName
.buf
[0] != '?'))
636 /* Redirect it to the relay-tracing trampoline */
639 fprintf(fileDest
, "=");
640 sprintf(buf
, "$relaytrace$%.*s", pexp
->strName
.len
, pexp
->strName
.buf
);
642 strTarget
.len
= pexp
->strName
.len
+ 12;
643 PrintName(fileDest
, pexp
, &strTarget
, 1);
647 /* Special handling for stdcall and fastcall */
648 if ((giArch
== ARCH_X86
) &&
649 ((pexp
->nCallingConvention
== CC_STDCALL
) ||
650 (pexp
->nCallingConvention
== CC_FASTCALL
)))
652 /* Is this the import lib? */
655 /* Is the name in the spec file decorated? */
656 const char* pcDeco
= ScanToken(pexp
->strName
.buf
, '@');
657 if (pcDeco
&& (pcDeco
< pexp
->strName
.buf
+ pexp
->strName
.len
))
659 /* Write the name including the leading @ */
660 fprintf(fileDest
, "==%.*s", pexp
->strName
.len
, pexp
->strName
.buf
);
663 else if ((!pexp
->strTarget
.buf
) && !(bTracing
))
665 /* Write a forwarder to the actual decorated symbol */
666 fprintf(fileDest
, "=");
667 PrintName(fileDest
, pexp
, &pexp
->strName
, 1);
673 OutputLine_def(FILE *fileDest
, EXPORT
*pexp
)
675 DbgPrint("OutputLine_def: '%.*s'...\n", pexp
->strName
.len
, pexp
->strName
.buf
);
676 fprintf(fileDest
, " ");
679 OutputLine_def_MS(fileDest
, pexp
);
681 OutputLine_def_GCC(fileDest
, pexp
);
683 if (pexp
->uFlags
& FL_ORDINAL
)
685 fprintf(fileDest
, " @%d", pexp
->nOrdinal
);
688 if (pexp
->uFlags
& FL_NONAME
)
690 fprintf(fileDest
, " NONAME");
693 /* Either PRIVATE or DATA */
694 if (pexp
->uFlags
& FL_PRIVATE
)
696 fprintf(fileDest
, " PRIVATE");
698 else if (pexp
->nCallingConvention
== CC_EXTERN
)
700 fprintf(fileDest
, " DATA");
703 fprintf(fileDest
, "\n");
709 ParseFile(char* pcStart
, FILE *fileDest
, PFNOUTLINE OutputLine
)
714 int included
, version_included
;
718 //fprintf(stderr, "info: line %d, pcStart:'%.30s'\n", nLine, pcStart);
723 for (pcLine
= pcStart
; *pcLine
; pcLine
= NextLine(pcLine
), nLine
++)
731 /* Skip white spaces */
732 while (*pc
== ' ' || *pc
== '\t') pc
++;
734 /* Skip empty lines, stop at EOF */
735 if (*pc
== ';' || *pc
<= '#') continue;
736 if (*pc
== 0) return 0;
738 /* Now we should get either an ordinal or @ */
743 exp
.nOrdinal
= atol(pc
);
744 /* The import lib should contain the ordinal only if -ordinal was specified */
746 exp
.uFlags
|= FL_ORDINAL
;
749 /* Go to next token (type) */
750 if (!(pc
= NextToken(pc
)))
752 fprintf(stderr
, "%s line %d: error: unexpected end of line\n", pszSourceFileName
, nLine
);
756 //fprintf(stderr, "info: Token:'%.*s'\n", TokenLength(pc), pc);
758 /* Now we should get the type */
759 if (CompareToken(pc
, "stdcall"))
761 exp
.nCallingConvention
= CC_STDCALL
;
763 else if (CompareToken(pc
, "cdecl") ||
764 CompareToken(pc
, "varargs"))
766 exp
.nCallingConvention
= CC_CDECL
;
768 else if (CompareToken(pc
, "fastcall"))
770 exp
.nCallingConvention
= CC_FASTCALL
;
772 else if (CompareToken(pc
, "thiscall"))
774 exp
.nCallingConvention
= CC_THISCALL
;
776 else if (CompareToken(pc
, "extern"))
778 exp
.nCallingConvention
= CC_EXTERN
;
780 else if (CompareToken(pc
, "stub"))
782 exp
.nCallingConvention
= CC_STUB
;
786 fprintf(stderr
, "%s line %d: error: expected callconv, got '%.*s' %d\n",
787 pszSourceFileName
, nLine
, TokenLength(pc
), pc
, *pc
);
791 /* Go to next token (options or name) */
792 if (!(pc
= NextToken(pc
)))
794 fprintf(stderr
, "fail2\n");
800 version_included
= 1;
803 if (CompareToken(pc
, "-arch="))
805 /* Default to not included */
809 /* Look if we are included */
813 if (CompareToken(pc
, pszArchString
) ||
814 CompareToken(pc
, pszArchString2
))
819 /* Skip to next arch or end */
820 while (*pc
> ',') pc
++;
821 } while (*pc
== ',');
823 else if (CompareToken(pc
, "-i386"))
825 if (giArch
!= ARCH_X86
) included
= 0;
827 else if (CompareToken(pc
, "-version="))
829 /* Default to not included */
830 version_included
= 0;
833 /* Look if we are included */
836 unsigned version
, endversion
;
838 /* Optionally skip leading '0x' */
840 if ((pc
[0] == '0') && (pc
[1] == 'x')) pc
+= 2;
842 /* Now get the version number */
843 endversion
= version
= strtoul(pc
, &pc
, 16);
845 /* Check if it's a range */
851 else if (pc
[0] == '-')
853 /* Optionally skip leading '0x' */
855 if ((pc
[0] == '0') && (pc
[1] == 'x')) pc
+= 2;
856 endversion
= strtoul(pc
, &pc
, 16);
859 /* Check for degenerate range */
860 if (version
> endversion
)
862 fprintf(stderr
, "%s line %d: error: invalid version rangen\n", pszSourceFileName
, nLine
);
866 /* Now compare the range with our version */
867 if ((guOsVersion
>= version
) &&
868 (guOsVersion
<= endversion
))
870 version_included
= 1;
873 /* Skip to next arch or end */
874 while (*pc
> ',') pc
++;
876 } while (*pc
== ',');
878 else if (CompareToken(pc
, "-private"))
880 exp
.uFlags
|= FL_PRIVATE
;
882 else if (CompareToken(pc
, "-noname"))
884 exp
.uFlags
|= FL_ORDINAL
| FL_NONAME
;
886 else if (CompareToken(pc
, "-ordinal"))
888 exp
.uFlags
|= FL_ORDINAL
;
889 /* GCC doesn't automatically import by ordinal if an ordinal
890 * is found in the def file. Force it. */
891 if (gbImportLib
&& !gbMSComp
)
892 exp
.uFlags
|= FL_NONAME
;
894 else if (CompareToken(pc
, "-stub"))
896 exp
.uFlags
|= FL_STUB
;
898 else if (CompareToken(pc
, "-norelay"))
900 exp
.uFlags
|= FL_NORELAY
;
902 else if (CompareToken(pc
, "-ret64"))
904 exp
.uFlags
|= FL_RET64
;
906 else if (CompareToken(pc
, "-register"))
908 exp
.uFlags
|= FL_REGISTER
;
912 fprintf(stderr
, "info: ignored option: '%.*s'\n",
913 TokenLength(pc
), pc
);
916 /* Go to next token */
920 //fprintf(stderr, "info: Name:'%.10s'\n", pc);
922 /* If arch didn't match ours, skip this entry */
923 if (!included
|| !version_included
) continue;
926 exp
.strName
.buf
= pc
;
927 exp
.strName
.len
= TokenLength(pc
);
928 DbgPrint("Got name: '%.*s'\n", exp
.strName
.len
, exp
.strName
.buf
);
930 /* Check for autoname */
931 if ((exp
.strName
.len
== 1) && (exp
.strName
.buf
[0] == '@'))
933 sprintf(namebuffer
, "ordinal%d", exp
.nOrdinal
);
934 exp
.strName
.len
= strlen(namebuffer
);
935 exp
.strName
.buf
= namebuffer
;
936 exp
.uFlags
|= FL_ORDINAL
| FL_NONAME
;
939 /* Handle parameters */
941 if (exp
.nCallingConvention
!= CC_EXTERN
&&
942 exp
.nCallingConvention
!= CC_STUB
)
944 /* Go to next token */
945 if (!(pc
= NextToken(pc
)))
947 fprintf(stderr
, "%s line %d: error: expected token\n", pszSourceFileName
, nLine
);
954 fprintf(stderr
, "%s line %d: error: expected '('\n", pszSourceFileName
, nLine
);
958 /* Skip whitespaces */
959 while (*pc
== ' ' || *pc
== '\t') pc
++;
964 if (CompareToken(pc
, "long"))
966 exp
.nStackBytes
+= 4;
967 exp
.anArgs
[exp
.nArgCount
] = ARG_LONG
;
969 else if (CompareToken(pc
, "double"))
971 exp
.nStackBytes
+= 8;
972 exp
.anArgs
[exp
.nArgCount
] = ARG_DBL
;
974 else if (CompareToken(pc
, "ptr"))
976 exp
.nStackBytes
+= 4; // sizeof(void*) on x86
977 exp
.anArgs
[exp
.nArgCount
] = ARG_PTR
;
979 else if (CompareToken(pc
, "str"))
981 exp
.nStackBytes
+= 4; // sizeof(void*) on x86
982 exp
.anArgs
[exp
.nArgCount
] = ARG_STR
;
984 else if (CompareToken(pc
, "wstr"))
986 exp
.nStackBytes
+= 4; // sizeof(void*) on x86
987 exp
.anArgs
[exp
.nArgCount
] = ARG_WSTR
;
989 else if (CompareToken(pc
, "int64"))
991 exp
.nStackBytes
+= 8;
992 exp
.anArgs
[exp
.nArgCount
] = ARG_INT64
;
994 else if (CompareToken(pc
, "int128"))
996 exp
.nStackBytes
+= 16;
997 exp
.anArgs
[exp
.nArgCount
] = ARG_INT128
;
999 else if (CompareToken(pc
, "float"))
1001 exp
.nStackBytes
+= 4;
1002 exp
.anArgs
[exp
.nArgCount
] = ARG_FLOAT
;
1005 fprintf(stderr
, "%s line %d: error: expected type, got: %.10s\n", pszSourceFileName
, nLine
, pc
);
1009 /* Go to next parameter */
1010 if (!(pc
= NextToken(pc
)))
1012 fprintf(stderr
, "fail5\n");
1020 fprintf(stderr
, "%s line %d: error: expected ')'\n", pszSourceFileName
, nLine
);
1025 /* Handle special stub cases */
1026 if (exp
.nCallingConvention
== CC_STUB
)
1028 /* Check for c++ mangled name */
1031 //printf("Found c++ mangled name...\n");
1036 /* Check for stdcall name */
1037 const char *p
= ScanToken(pc
, '@');
1038 if (p
&& (p
- pc
< exp
.strName
.len
))
1042 /* Truncate the name to before the @ */
1043 exp
.strName
.len
= (int)(p
- pc
);
1044 if (exp
.strName
.len
< 1)
1046 fprintf(stderr
, "%s line %d: error: unexpected @ found\n", pszSourceFileName
, nLine
);
1049 exp
.nStackBytes
= atoi(p
+ 1);
1050 exp
.nArgCount
= exp
.nStackBytes
/ 4;
1051 exp
.nCallingConvention
= CC_STDCALL
;
1052 exp
.uFlags
|= FL_STUB
;
1053 for (i
= 0; i
< exp
.nArgCount
; i
++)
1054 exp
.anArgs
[i
] = ARG_LONG
;
1059 /* Get optional redirection */
1063 exp
.strTarget
.buf
= pc
;
1064 exp
.strTarget
.len
= TokenLength(pc
);
1066 /* Check syntax (end of line) */
1069 fprintf(stderr
, "%s line %d: error: additional tokens after ')'\n", pszSourceFileName
, nLine
);
1073 /* Don't relay-trace forwarded functions */
1074 exp
.uFlags
|= FL_NORELAY
;
1078 exp
.strTarget
.buf
= NULL
;
1079 exp
.strTarget
.len
= 0;
1082 /* Check for no-name without ordinal */
1083 if ((exp
.uFlags
& FL_ORDINAL
) && (exp
.nOrdinal
== -1))
1085 fprintf(stderr
, "%s line %d: error: ordinal export without ordinal!\n", pszSourceFileName
, nLine
);
1089 if (!gbMSComp
&& !gbNotPrivateNoWarn
&& gbImportLib
&& !(exp
.uFlags
& FL_PRIVATE
))
1091 for (i
= 0; i
< ARRAYSIZE(astrShouldBePrivate
); i
++)
1093 if (strlen(astrShouldBePrivate
[i
]) == exp
.strName
.len
&&
1094 strncmp(exp
.strName
.buf
, astrShouldBePrivate
[i
], exp
.strName
.len
) == 0)
1096 fprintf(stderr
, "%s line %d: warning: export of '%.*s' should be PRIVATE\n",
1097 pszSourceFileName
, nLine
, exp
.strName
.len
, exp
.strName
.buf
);
1102 OutputLine(fileDest
, &exp
);
1111 printf("syntax: spec2def [<options> ...] <spec file>\n"
1112 "Possible options:\n"
1113 " -h --help print this help screen\n"
1114 " -l=<file> generate an asm lib stub\n"
1115 " -d=<file> generate a def file\n"
1116 " -s=<file> generate a stub file\n"
1117 " --ms MSVC compatibility\n"
1118 " -n=<name> name of the dll\n"
1119 " --implib generate a def file for an import library\n"
1120 " --no-private-warnings suppress warnings about symbols that should be -private\n"
1121 " -a=<arch> set architecture to <arch> (i386, x86_64, arm)\n"
1122 " --with-tracing generate wine-like \"+relay\" trace trampolines (needs -s)\n");
1125 int main(int argc
, char *argv
[])
1128 char *pszSource
, *pszDefFileName
= NULL
, *pszStubFileName
= NULL
, *pszLibStubName
= NULL
;
1129 char achDllName
[40];
1140 for (i
= 1; i
< argc
&& *argv
[i
] == '-'; i
++)
1142 if ((strcasecmp(argv
[i
], "--help") == 0) ||
1143 (strcasecmp(argv
[i
], "-h") == 0))
1148 else if (argv
[i
][1] == 'd' && argv
[i
][2] == '=')
1150 pszDefFileName
= argv
[i
] + 3;
1152 else if (argv
[i
][1] == 'l' && argv
[i
][2] == '=')
1154 pszLibStubName
= argv
[i
] + 3;
1156 else if (argv
[i
][1] == 's' && argv
[i
][2] == '=')
1158 pszStubFileName
= argv
[i
] + 3;
1160 else if (argv
[i
][1] == 'n' && argv
[i
][2] == '=')
1162 pszDllName
= argv
[i
] + 3;
1164 else if (strcasecmp(argv
[i
], "--version=0x") == 0)
1166 guOsVersion
= strtoul(argv
[i
] + sizeof("--version=0x"), NULL
, 16);
1168 else if (strcasecmp(argv
[i
], "--implib") == 0)
1172 else if (strcasecmp(argv
[i
], "--ms") == 0)
1176 else if (strcasecmp(argv
[i
], "--no-private-warnings") == 0)
1178 gbNotPrivateNoWarn
= 1;
1180 else if (strcasecmp(argv
[i
], "--with-tracing") == 0)
1182 if (!pszStubFileName
)
1184 fprintf(stderr
, "Error: cannot use --with-tracing without -s option.\n");
1189 else if (argv
[i
][1] == 'a' && argv
[i
][2] == '=')
1191 pszArchString
= argv
[i
] + 3;
1195 fprintf(stderr
, "Unrecognized option: %s\n", argv
[i
]);
1200 if (strcasecmp(pszArchString
, "i386") == 0)
1203 gpszUnderscore
= "_";
1205 else if (strcasecmp(pszArchString
, "x86_64") == 0) giArch
= ARCH_AMD64
;
1206 else if (strcasecmp(pszArchString
, "ia64") == 0) giArch
= ARCH_IA64
;
1207 else if (strcasecmp(pszArchString
, "arm") == 0) giArch
= ARCH_ARM
;
1208 else if (strcasecmp(pszArchString
, "ppc") == 0) giArch
= ARCH_PPC
;
1210 if ((giArch
== ARCH_AMD64
) || (giArch
== ARCH_IA64
))
1212 pszArchString2
= "win64";
1215 pszArchString2
= "win32";
1217 /* Set a default dll name */
1223 p1
= strrchr(argv
[i
], '\\');
1224 if (!p1
) p1
= strrchr(argv
[i
], '/');
1225 p2
= p1
= p1
? p1
+ 1 : argv
[i
];
1227 /* walk up to '.' */
1228 while (*p2
!= '.' && *p2
!= 0) p2
++;
1230 if (len
>= sizeof(achDllName
) - 5)
1232 fprintf(stderr
, "name too long: %s\n", p1
);
1236 strncpy(achDllName
, p1
, len
);
1237 strncpy(achDllName
+ len
, ".dll", sizeof(achDllName
) - len
);
1238 pszDllName
= achDllName
;
1241 /* Open input file */
1242 pszSourceFileName
= argv
[i
];
1243 file
= fopen(pszSourceFileName
, "r");
1246 fprintf(stderr
, "error: could not open file %s\n", pszSourceFileName
);
1251 fseek(file
, 0, SEEK_END
);
1252 nFileSize
= ftell(file
);
1255 /* Allocate memory buffer */
1256 pszSource
= malloc(nFileSize
+ 1);
1263 /* Load input file into memory */
1264 nFileSize
= fread(pszSource
, 1, nFileSize
, file
);
1267 /* Zero terminate the source */
1268 pszSource
[nFileSize
] = '\0';
1272 /* Open output file */
1273 file
= fopen(pszDefFileName
, "w");
1276 fprintf(stderr
, "error: could not open output file %s\n", argv
[i
+ 1]);
1280 OutputHeader_def(file
, pszDllName
);
1281 result
= ParseFile(pszSource
, file
, OutputLine_def
);
1285 if (pszStubFileName
)
1287 /* Open output file */
1288 file
= fopen(pszStubFileName
, "w");
1291 fprintf(stderr
, "error: could not open output file %s\n", argv
[i
+ 1]);
1295 OutputHeader_stub(file
);
1296 result
= ParseFile(pszSource
, file
, OutputLine_stub
);
1302 /* Open output file */
1303 file
= fopen(pszLibStubName
, "w");
1306 fprintf(stderr
, "error: could not open output file %s\n", argv
[i
+ 1]);
1310 OutputHeader_asmstub(file
, pszDllName
);
1311 result
= ParseFile(pszSource
, file
, OutputLine_asmstub
);
1312 fprintf(file
, "\n END\n");