7 #define strcasecmp(_String1, _String2) _stricmp(_String1, _String2)
8 #define strncasecmp(_String1, _String2, _MaxCount) _strnicmp(_String1, _String2, _MaxCount)
11 #define ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0]))
13 typedef struct _STRING
23 int nCallingConvention
;
41 typedef int (*PFNOUTLINE
)(FILE *, EXPORT
*);
44 int gbNotPrivateNoWarn
= 0;
46 int giArch
= ARCH_X86
;
47 char *pszArchString
= "i386";
49 char *pszSourceFileName
= NULL
;
50 char *pszDllName
= NULL
;
51 char *gpszUnderscore
= "";
53 unsigned guOsVersion
= 0x502;
54 #define DbgPrint(...) (!gbDebug || fprintf(stderr, __VA_ARGS__))
89 const char* astrCallingConventions
[] =
99 * List of OLE exports that should be PRIVATE and not be assigned an ordinal.
100 * In case these conditions are not met when linking with MS LINK.EXE, warnings
101 * LNK4104 and LNK4222 respectively are emitted.
103 static const char* astrOlePrivateExports
[] =
107 "DllGetClassFactoryFromClassString",
108 "DllGetDocumentation",
112 "DllRegisterServerEx",
113 "DllRegisterServerExW",
115 "DllUnregisterServer",
116 "RasCustomDeleteEntryNotify",
124 IsSeparator(char chr
)
126 return ((chr
<= ',' && chr
!= '$' && chr
!= '#') ||
127 (chr
>= ':' && chr
< '?') );
131 CompareToken(const char *token
, const char *comparand
)
135 if (*token
!= *comparand
) return 0;
139 if (IsSeparator(comparand
[-1])) return 1;
140 if (!IsSeparator(*token
)) return 0;
145 ScanToken(const char *token
, char chr
)
147 while (!IsSeparator(*token
))
149 if (*token
== chr
) return token
;
160 if (pc
[0] == '\n' && pc
[1] == '\r') return pc
+ 2;
161 else if (pc
[0] == '\n') return pc
+ 1;
168 TokenLength(char *pc
)
172 while (!IsSeparator(*pc
++)) length
++;
181 while (!IsSeparator(*pc
)) pc
++;
183 /* Skip white spaces */
184 while (*pc
== ' ' || *pc
== '\t') pc
++;
186 /* Check for end of line */
187 if (*pc
== '\n' || *pc
== '\r' || *pc
== 0) return 0;
189 /* Check for comment */
190 if (*pc
== '#' || *pc
== ';') return 0;
196 OutputHeader_stub(FILE *file
)
198 fprintf(file
, "/* This file is autogenerated, do not edit. */\n\n"
199 "#include <stubs.h>\n");
203 fprintf(file
, "#include <wine/debug.h>\n");
204 fprintf(file
, "#include <inttypes.h>\n");
205 fprintf(file
, "WINE_DECLARE_DEBUG_CHANNEL(relay);\n");
212 OutputLine_stub(FILE *file
, EXPORT
*pexp
)
216 int bInPrototype
= 0;
218 if (pexp
->nCallingConvention
!= CC_STUB
&&
219 (pexp
->uFlags
& FL_STUB
) == 0)
221 /* Only relay trace stdcall C functions */
222 if (!gbTracing
|| (pexp
->nCallingConvention
!= CC_STDCALL
)
223 || (pexp
->uFlags
& FL_NORELAY
)
224 || (pexp
->strName
.buf
[0] == '?'))
231 /* Declare the "real" function */
234 fprintf(file
, "extern ");
240 if (pexp
->uFlags
& FL_REGISTER
)
242 /* FIXME: Not sure this is right */
243 fprintf(file
, "void ");
245 else if (pexp
->uFlags
& FL_RET64
)
247 fprintf(file
, "__int64 ");
251 fprintf(file
, "int ");
254 if ((giArch
== ARCH_X86
) &&
255 pexp
->nCallingConvention
== CC_STDCALL
)
257 fprintf(file
, "__stdcall ");
261 if (pexp
->strName
.buf
[0] == '?')
263 fprintf(file
, "stub_function%d(", pexp
->nNumber
);
267 if (!bRelay
|| bInPrototype
)
268 fprintf(file
, "%.*s(", pexp
->strName
.len
, pexp
->strName
.buf
);
270 fprintf(file
, "$relaytrace$%.*s(", pexp
->strName
.len
, pexp
->strName
.buf
);
273 for (i
= 0; i
< pexp
->nArgCount
; i
++)
275 if (i
!= 0) fprintf(file
, ", ");
276 switch (pexp
->anArgs
[i
])
278 case ARG_LONG
: fprintf(file
, "long"); break;
279 case ARG_PTR
: fprintf(file
, "void*"); break;
280 case ARG_STR
: fprintf(file
, "char*"); break;
281 case ARG_WSTR
: fprintf(file
, "wchar_t*"); break;
282 case ARG_DBL
: fprintf(file
, "double"); break;
283 case ARG_INT64
: fprintf(file
, "__int64"); break;
284 /* __int128 is not supported on x86, and int128 in spec files most often represents a GUID */
285 case ARG_INT128
: fprintf(file
, "GUID"); break;
286 case ARG_FLOAT
: fprintf(file
, "float"); break;
288 fprintf(file
, " a%d", i
);
293 fprintf(file
, ");\n\n");
295 } while (bInPrototype
--);
299 fprintf(file
, ")\n{\n\tDbgPrint(\"WARNING: calling stub %.*s(",
300 pexp
->strName
.len
, pexp
->strName
.buf
);
304 fprintf(file
, ")\n{\n");
305 if (pexp
->uFlags
& FL_REGISTER
)
307 /* No return value */
309 else if (pexp
->uFlags
& FL_RET64
)
311 fprintf(file
, "\t__int64 retval;\n");
315 fprintf(file
, "\tint retval;\n");
317 fprintf(file
, "\tif (TRACE_ON(relay))\n\t\tDPRINTF(\"%s: %.*s(",
318 pszDllName
, pexp
->strName
.len
, pexp
->strName
.buf
);
321 for (i
= 0; i
< pexp
->nArgCount
; i
++)
323 if (i
!= 0) fprintf(file
, ",");
324 switch (pexp
->anArgs
[i
])
326 case ARG_LONG
: fprintf(file
, "0x%%lx"); break;
327 case ARG_PTR
: fprintf(file
, "0x%%p"); break;
328 case ARG_STR
: fprintf(file
, "'%%s'"); break;
329 case ARG_WSTR
: fprintf(file
, "'%%ws'"); break;
330 case ARG_DBL
: fprintf(file
, "%%f"); break;
331 case ARG_INT64
: fprintf(file
, "%%\"PRIx64\""); break;
332 case ARG_INT128
: fprintf(file
, "'%%s'"); break;
333 case ARG_FLOAT
: fprintf(file
, "%%f"); break;
336 fprintf(file
, ")\\n\"");
338 for (i
= 0; i
< pexp
->nArgCount
; i
++)
341 switch (pexp
->anArgs
[i
])
343 case ARG_LONG
: fprintf(file
, "(long)a%d", i
); break;
344 case ARG_PTR
: fprintf(file
, "(void*)a%d", i
); break;
345 case ARG_STR
: fprintf(file
, "(char*)a%d", i
); break;
346 case ARG_WSTR
: fprintf(file
, "(wchar_t*)a%d", i
); break;
347 case ARG_DBL
: fprintf(file
, "(double)a%d", i
); break;
348 case ARG_INT64
: fprintf(file
, "(__int64)a%d", i
); break;
349 case ARG_INT128
: fprintf(file
, "wine_dbgstr_guid(&a%d)", i
); break;
350 case ARG_FLOAT
: fprintf(file
, "(float)a%d", i
); break;
353 fprintf(file
, ");\n");
355 if (pexp
->nCallingConvention
== CC_STUB
)
357 fprintf(file
, "\t__wine_spec_unimplemented_stub(\"%s\", __FUNCTION__);\n", pszDllName
);
361 if (pexp
->uFlags
& FL_REGISTER
)
367 fprintf(file
, "\tretval = ");
369 fprintf(file
, "%.*s(", pexp
->strName
.len
, pexp
->strName
.buf
);
371 for (i
= 0; i
< pexp
->nArgCount
; i
++)
373 if (i
!= 0) fprintf(file
, ", ");
374 fprintf(file
, "a%d", i
);
376 fprintf(file
, ");\n");
380 fprintf(file
, "\treturn 0;\n}\n\n");
381 else if ((pexp
->uFlags
& FL_REGISTER
) == 0)
383 if (pexp
->uFlags
& FL_RET64
)
385 fprintf(file
, "\tif (TRACE_ON(relay))\n\t\tDPRINTF(\"%s: %.*s: retval = %%\"PRIx64\"\\n\", retval);\n",
386 pszDllName
, pexp
->strName
.len
, pexp
->strName
.buf
);
390 fprintf(file
, "\tif (TRACE_ON(relay))\n\t\tDPRINTF(\"%s: %.*s: retval = 0x%%lx\\n\", retval);\n",
391 pszDllName
, pexp
->strName
.len
, pexp
->strName
.buf
);
393 fprintf(file
, "\treturn retval;\n}\n\n");
400 OutputHeader_asmstub(FILE *file
, char *libname
)
402 fprintf(file
, "; File generated automatically, do not edit! \n\n");
404 if (giArch
== ARCH_X86
)
406 fprintf(file
, ".586\n.model flat\n.code\n");
408 else if (giArch
== ARCH_AMD64
)
410 fprintf(file
, ".code\n");
412 else if (giArch
== ARCH_ARM
)
414 fprintf(file
, " AREA |.text|,ALIGN=2,CODE,READONLY\n\n");
419 Output_stublabel(FILE *fileDest
, char* pszSymbolName
)
421 if (giArch
== ARCH_ARM
)
424 "\tEXPORT |%s| [FUNC]\n|%s|\n",
431 "PUBLIC %s\n%s: nop\n",
438 OutputLine_asmstub(FILE *fileDest
, EXPORT
*pexp
)
440 char szNameBuffer
[128];
442 /* Handle autoname */
443 if (pexp
->strName
.len
== 1 && pexp
->strName
.buf
[0] == '@')
445 sprintf(szNameBuffer
, "%sordinal%d\n%sordinal%d: nop\n",
446 gpszUnderscore
, pexp
->nOrdinal
, gpszUnderscore
, pexp
->nOrdinal
);
448 else if (giArch
!= ARCH_X86
)
450 sprintf(szNameBuffer
, "_stub_%.*s",
451 pexp
->strName
.len
, pexp
->strName
.buf
);
453 else if (pexp
->nCallingConvention
== CC_STDCALL
)
455 sprintf(szNameBuffer
, "__stub_%.*s@%d",
456 pexp
->strName
.len
, pexp
->strName
.buf
, pexp
->nStackBytes
);
458 else if (pexp
->nCallingConvention
== CC_FASTCALL
)
460 sprintf(szNameBuffer
, "@_stub_%.*s@%d",
461 pexp
->strName
.len
, pexp
->strName
.buf
, pexp
->nStackBytes
);
463 else if ((pexp
->nCallingConvention
== CC_CDECL
) ||
464 (pexp
->nCallingConvention
== CC_THISCALL
) ||
465 (pexp
->nCallingConvention
== CC_EXTERN
) ||
466 (pexp
->nCallingConvention
== CC_STUB
))
468 sprintf(szNameBuffer
, "__stub_%.*s",
469 pexp
->strName
.len
, pexp
->strName
.buf
);
473 fprintf(stderr
, "Invalid calling convention");
477 Output_stublabel(fileDest
, szNameBuffer
);
483 OutputHeader_def(FILE *file
, char *libname
)
486 "; File generated automatically, do not edit!\n\n"
493 PrintName(FILE *fileDest
, EXPORT
*pexp
, PSTRING pstr
, int fDeco
)
495 const char *pcName
= pstr
->buf
;
496 int nNameLength
= pstr
->len
;
497 const char* pcDot
, *pcAt
;
499 /* Check for non-x86 first */
500 if (giArch
!= ARCH_X86
)
502 /* Does the string already have stdcall decoration? */
503 pcAt
= ScanToken(pcName
, '@');
504 if (pcAt
&& (pcAt
< (pcName
+ nNameLength
)) && (pcName
[0] == '_'))
506 /* Skip leading underscore and remove trailing decoration */
508 nNameLength
= (int)(pcAt
- pcName
);
511 /* Print the undecorated function name */
512 fprintf(fileDest
, "%.*s", nNameLength
, pcName
);
515 ((pexp
->nCallingConvention
== CC_STDCALL
) ||
516 (pexp
->nCallingConvention
== CC_FASTCALL
)))
518 /* Scan for a dll forwarding dot */
519 pcDot
= ScanToken(pcName
, '.');
522 /* First print the dll name, followed by a dot */
523 nNameLength
= (int)(pcDot
- pcName
);
524 fprintf(fileDest
, "%.*s.", nNameLength
, pcName
);
526 /* Now the actual function name */
528 nNameLength
= pexp
->strTarget
.len
- nNameLength
- 1;
531 /* Does the string already have decoration? */
532 pcAt
= ScanToken(pcName
, '@');
533 if (pcAt
&& (pcAt
< (pcName
+ nNameLength
)))
535 /* On GCC, we need to remove the leading stdcall underscore */
536 if (!gbMSComp
&& (pexp
->nCallingConvention
== CC_STDCALL
))
542 /* Print the already decorated function name */
543 fprintf(fileDest
, "%.*s", nNameLength
, pcName
);
547 /* Print the prefix, but skip it for (GCC && stdcall) */
548 if (gbMSComp
|| (pexp
->nCallingConvention
!= CC_STDCALL
))
550 fprintf(fileDest
, "%c", pexp
->nCallingConvention
== CC_FASTCALL
? '@' : '_');
553 /* Print the name with trailing decoration */
554 fprintf(fileDest
, "%.*s@%d", nNameLength
, pcName
, pexp
->nStackBytes
);
559 /* Print the undecorated function name */
560 fprintf(fileDest
, "%.*s", nNameLength
, pcName
);
565 OutputLine_def_MS(FILE *fileDest
, EXPORT
*pexp
)
567 PrintName(fileDest
, pexp
, &pexp
->strName
, 0);
571 /* Redirect to a stub function, to get the right decoration in the lib */
572 fprintf(fileDest
, "=_stub_%.*s", pexp
->strName
.len
, pexp
->strName
.buf
);
574 else if (pexp
->strTarget
.buf
)
576 if (pexp
->strName
.buf
[0] == '?')
578 //fprintf(stderr, "warning: ignoring C++ redirection %.*s -> %.*s\n",
579 // pexp->strName.len, pexp->strName.buf, pexp->strTarget.len, pexp->strTarget.buf);
583 fprintf(fileDest
, "=");
585 /* If the original name was decorated, use decoration in the forwarder as well */
586 if ((giArch
== ARCH_X86
) && ScanToken(pexp
->strName
.buf
, '@') &&
587 !ScanToken(pexp
->strTarget
.buf
, '@') &&
588 ((pexp
->nCallingConvention
== CC_STDCALL
) ||
589 (pexp
->nCallingConvention
== CC_FASTCALL
)) )
591 PrintName(fileDest
, pexp
, &pexp
->strTarget
, 1);
595 /* Write the undecorated redirection name */
596 fprintf(fileDest
, "%.*s", pexp
->strTarget
.len
, pexp
->strTarget
.buf
);
600 else if (((pexp
->uFlags
& FL_STUB
) || (pexp
->nCallingConvention
== CC_STUB
)) &&
601 (pexp
->strName
.buf
[0] == '?'))
603 /* C++ stubs are forwarded to C stubs */
604 fprintf(fileDest
, "=stub_function%d", pexp
->nNumber
);
606 else if (gbTracing
&& ((pexp
->uFlags
& FL_NORELAY
) == 0) && (pexp
->nCallingConvention
== CC_STDCALL
) &&
607 (pexp
->strName
.buf
[0] != '?'))
609 /* Redirect it to the relay-tracing trampoline */
610 fprintf(fileDest
, "=$relaytrace$%.*s", pexp
->strName
.len
, pexp
->strName
.buf
);
615 OutputLine_def_GCC(FILE *fileDest
, EXPORT
*pexp
)
618 /* Print the function name, with decoration for export libs */
619 PrintName(fileDest
, pexp
, &pexp
->strName
, gbImportLib
);
620 DbgPrint("Generating def line for '%.*s'\n", pexp
->strName
.len
, pexp
->strName
.buf
);
622 /* Check if this is a forwarded export */
623 if (pexp
->strTarget
.buf
)
625 int fIsExternal
= !!ScanToken(pexp
->strTarget
.buf
, '.');
626 DbgPrint("Got redirect '%.*s'\n", pexp
->strTarget
.len
, pexp
->strTarget
.buf
);
628 /* print the target name, don't decorate if it is external */
629 fprintf(fileDest
, "=");
630 PrintName(fileDest
, pexp
, &pexp
->strTarget
, !fIsExternal
);
632 else if (((pexp
->uFlags
& FL_STUB
) || (pexp
->nCallingConvention
== CC_STUB
)) &&
633 (pexp
->strName
.buf
[0] == '?'))
635 /* C++ stubs are forwarded to C stubs */
636 fprintf(fileDest
, "=stub_function%d", pexp
->nNumber
);
638 else if (gbTracing
&& ((pexp
->uFlags
& FL_NORELAY
) == 0) &&
639 (pexp
->nCallingConvention
== CC_STDCALL
) &&
640 (pexp
->strName
.buf
[0] != '?'))
642 /* Redirect it to the relay-tracing trampoline */
645 fprintf(fileDest
, "=");
646 sprintf(buf
, "$relaytrace$%.*s", pexp
->strName
.len
, pexp
->strName
.buf
);
648 strTarget
.len
= pexp
->strName
.len
+ 12;
649 PrintName(fileDest
, pexp
, &strTarget
, 1);
653 /* Special handling for stdcall and fastcall */
654 if ((giArch
== ARCH_X86
) &&
655 ((pexp
->nCallingConvention
== CC_STDCALL
) ||
656 (pexp
->nCallingConvention
== CC_FASTCALL
)))
658 /* Is this the import lib? */
661 /* Is the name in the spec file decorated? */
662 const char* pcDeco
= ScanToken(pexp
->strName
.buf
, '@');
663 if (pcDeco
&& (pcDeco
< pexp
->strName
.buf
+ pexp
->strName
.len
))
665 /* Write the name including the leading @ */
666 fprintf(fileDest
, "==%.*s", pexp
->strName
.len
, pexp
->strName
.buf
);
669 else if ((!pexp
->strTarget
.buf
) && !(bTracing
))
671 /* Write a forwarder to the actual decorated symbol */
672 fprintf(fileDest
, "=");
673 PrintName(fileDest
, pexp
, &pexp
->strName
, 1);
679 OutputLine_def(FILE *fileDest
, EXPORT
*pexp
)
681 DbgPrint("OutputLine_def: '%.*s'...\n", pexp
->strName
.len
, pexp
->strName
.buf
);
682 fprintf(fileDest
, " ");
685 OutputLine_def_MS(fileDest
, pexp
);
687 OutputLine_def_GCC(fileDest
, pexp
);
689 if (pexp
->uFlags
& FL_ORDINAL
)
691 fprintf(fileDest
, " @%d", pexp
->nOrdinal
);
694 if (pexp
->uFlags
& FL_NONAME
)
696 fprintf(fileDest
, " NONAME");
699 /* Either PRIVATE or DATA */
700 if (pexp
->uFlags
& FL_PRIVATE
)
702 fprintf(fileDest
, " PRIVATE");
704 else if (pexp
->nCallingConvention
== CC_EXTERN
)
706 fprintf(fileDest
, " DATA");
709 fprintf(fileDest
, "\n");
715 ParseFile(char* pcStart
, FILE *fileDest
, PFNOUTLINE OutputLine
)
720 int included
, version_included
;
724 //fprintf(stderr, "info: line %d, pcStart:'%.30s'\n", nLine, pcStart);
729 for (pcLine
= pcStart
; *pcLine
; pcLine
= NextLine(pcLine
), nLine
++)
737 /* Skip white spaces */
738 while (*pc
== ' ' || *pc
== '\t') pc
++;
740 /* Skip empty lines, stop at EOF */
741 if (*pc
== ';' || *pc
<= '#') continue;
742 if (*pc
== 0) return 0;
744 /* Now we should get either an ordinal or @ */
749 exp
.nOrdinal
= atol(pc
);
750 /* The import lib should contain the ordinal only if -ordinal was specified */
752 exp
.uFlags
|= FL_ORDINAL
;
755 /* Go to next token (type) */
756 if (!(pc
= NextToken(pc
)))
758 fprintf(stderr
, "%s line %d: error: unexpected end of line\n", pszSourceFileName
, nLine
);
762 //fprintf(stderr, "info: Token:'%.*s'\n", TokenLength(pc), pc);
764 /* Now we should get the type */
765 if (CompareToken(pc
, "stdcall"))
767 exp
.nCallingConvention
= CC_STDCALL
;
769 else if (CompareToken(pc
, "cdecl") ||
770 CompareToken(pc
, "varargs"))
772 exp
.nCallingConvention
= CC_CDECL
;
774 else if (CompareToken(pc
, "fastcall"))
776 exp
.nCallingConvention
= CC_FASTCALL
;
778 else if (CompareToken(pc
, "thiscall"))
780 exp
.nCallingConvention
= CC_THISCALL
;
782 else if (CompareToken(pc
, "extern"))
784 exp
.nCallingConvention
= CC_EXTERN
;
786 else if (CompareToken(pc
, "stub"))
788 exp
.nCallingConvention
= CC_STUB
;
792 fprintf(stderr
, "%s line %d: error: expected callconv, got '%.*s' %d\n",
793 pszSourceFileName
, nLine
, TokenLength(pc
), pc
, *pc
);
797 /* Go to next token (options or name) */
798 if (!(pc
= NextToken(pc
)))
800 fprintf(stderr
, "fail2\n");
806 version_included
= 1;
809 if (CompareToken(pc
, "-arch="))
811 /* Default to not included */
815 /* Look if we are included */
819 if (CompareToken(pc
, pszArchString
) ||
820 CompareToken(pc
, pszArchString2
))
825 /* Skip to next arch or end */
826 while (*pc
> ',') pc
++;
827 } while (*pc
== ',');
829 else if (CompareToken(pc
, "-i386"))
831 if (giArch
!= ARCH_X86
) included
= 0;
833 else if (CompareToken(pc
, "-version="))
835 /* Default to not included */
836 version_included
= 0;
839 /* Look if we are included */
842 unsigned version
, endversion
;
844 /* Optionally skip leading '0x' */
846 if ((pc
[0] == '0') && (pc
[1] == 'x')) pc
+= 2;
848 /* Now get the version number */
849 endversion
= version
= strtoul(pc
, &pc
, 16);
851 /* Check if it's a range */
857 else if (pc
[0] == '-')
859 /* Optionally skip leading '0x' */
861 if ((pc
[0] == '0') && (pc
[1] == 'x')) pc
+= 2;
862 endversion
= strtoul(pc
, &pc
, 16);
865 /* Check for degenerate range */
866 if (version
> endversion
)
868 fprintf(stderr
, "%s line %d: error: invalid version rangen\n", pszSourceFileName
, nLine
);
872 /* Now compare the range with our version */
873 if ((guOsVersion
>= version
) &&
874 (guOsVersion
<= endversion
))
876 version_included
= 1;
879 /* Skip to next arch or end */
880 while (*pc
> ',') pc
++;
882 } while (*pc
== ',');
884 else if (CompareToken(pc
, "-private"))
886 exp
.uFlags
|= FL_PRIVATE
;
888 else if (CompareToken(pc
, "-noname"))
890 exp
.uFlags
|= FL_ORDINAL
| FL_NONAME
;
892 else if (CompareToken(pc
, "-ordinal"))
894 exp
.uFlags
|= FL_ORDINAL
;
895 /* GCC doesn't automatically import by ordinal if an ordinal
896 * is found in the def file. Force it. */
897 if (gbImportLib
&& !gbMSComp
)
898 exp
.uFlags
|= FL_NONAME
;
900 else if (CompareToken(pc
, "-stub"))
902 exp
.uFlags
|= FL_STUB
;
904 else if (CompareToken(pc
, "-norelay"))
906 exp
.uFlags
|= FL_NORELAY
;
908 else if (CompareToken(pc
, "-ret64"))
910 exp
.uFlags
|= FL_RET64
;
912 else if (CompareToken(pc
, "-register"))
914 exp
.uFlags
|= FL_REGISTER
;
918 fprintf(stderr
, "info: ignored option: '%.*s'\n",
919 TokenLength(pc
), pc
);
922 /* Go to next token */
926 //fprintf(stderr, "info: Name:'%.10s'\n", pc);
928 /* If arch didn't match ours, skip this entry */
929 if (!included
|| !version_included
) continue;
932 exp
.strName
.buf
= pc
;
933 exp
.strName
.len
= TokenLength(pc
);
934 DbgPrint("Got name: '%.*s'\n", exp
.strName
.len
, exp
.strName
.buf
);
936 /* Check for autoname */
937 if ((exp
.strName
.len
== 1) && (exp
.strName
.buf
[0] == '@'))
939 sprintf(namebuffer
, "ordinal%d", exp
.nOrdinal
);
940 exp
.strName
.len
= strlen(namebuffer
);
941 exp
.strName
.buf
= namebuffer
;
942 exp
.uFlags
|= FL_ORDINAL
| FL_NONAME
;
945 /* Handle parameters */
947 if (exp
.nCallingConvention
!= CC_EXTERN
&&
948 exp
.nCallingConvention
!= CC_STUB
)
950 /* Go to next token */
951 if (!(pc
= NextToken(pc
)))
953 fprintf(stderr
, "%s line %d: error: expected token\n", pszSourceFileName
, nLine
);
960 fprintf(stderr
, "%s line %d: error: expected '('\n", pszSourceFileName
, nLine
);
964 /* Skip whitespaces */
965 while (*pc
== ' ' || *pc
== '\t') pc
++;
970 if (CompareToken(pc
, "long"))
972 exp
.nStackBytes
+= 4;
973 exp
.anArgs
[exp
.nArgCount
] = ARG_LONG
;
975 else if (CompareToken(pc
, "double"))
977 exp
.nStackBytes
+= 8;
978 exp
.anArgs
[exp
.nArgCount
] = ARG_DBL
;
980 else if (CompareToken(pc
, "ptr"))
982 exp
.nStackBytes
+= 4; // sizeof(void*) on x86
983 exp
.anArgs
[exp
.nArgCount
] = ARG_PTR
;
985 else if (CompareToken(pc
, "str"))
987 exp
.nStackBytes
+= 4; // sizeof(void*) on x86
988 exp
.anArgs
[exp
.nArgCount
] = ARG_STR
;
990 else if (CompareToken(pc
, "wstr"))
992 exp
.nStackBytes
+= 4; // sizeof(void*) on x86
993 exp
.anArgs
[exp
.nArgCount
] = ARG_WSTR
;
995 else if (CompareToken(pc
, "int64"))
997 exp
.nStackBytes
+= 8;
998 exp
.anArgs
[exp
.nArgCount
] = ARG_INT64
;
1000 else if (CompareToken(pc
, "int128"))
1002 exp
.nStackBytes
+= 16;
1003 exp
.anArgs
[exp
.nArgCount
] = ARG_INT128
;
1005 else if (CompareToken(pc
, "float"))
1007 exp
.nStackBytes
+= 4;
1008 exp
.anArgs
[exp
.nArgCount
] = ARG_FLOAT
;
1011 fprintf(stderr
, "%s line %d: error: expected type, got: %.10s\n", pszSourceFileName
, nLine
, pc
);
1015 /* Go to next parameter */
1016 if (!(pc
= NextToken(pc
)))
1018 fprintf(stderr
, "fail5\n");
1026 fprintf(stderr
, "%s line %d: error: expected ')'\n", pszSourceFileName
, nLine
);
1031 /* Handle special stub cases */
1032 if (exp
.nCallingConvention
== CC_STUB
)
1034 /* Check for c++ mangled name */
1037 //printf("Found c++ mangled name...\n");
1042 /* Check for stdcall name */
1043 const char *p
= ScanToken(pc
, '@');
1044 if (p
&& (p
- pc
< exp
.strName
.len
))
1048 /* Truncate the name to before the @ */
1049 exp
.strName
.len
= (int)(p
- pc
);
1050 if (exp
.strName
.len
< 1)
1052 fprintf(stderr
, "%s line %d: error: unexpected @ found\n", pszSourceFileName
, nLine
);
1055 exp
.nStackBytes
= atoi(p
+ 1);
1056 exp
.nArgCount
= exp
.nStackBytes
/ 4;
1057 exp
.nCallingConvention
= CC_STDCALL
;
1058 exp
.uFlags
|= FL_STUB
;
1059 for (i
= 0; i
< exp
.nArgCount
; i
++)
1060 exp
.anArgs
[i
] = ARG_LONG
;
1065 /* Get optional redirection */
1069 exp
.strTarget
.buf
= pc
;
1070 exp
.strTarget
.len
= TokenLength(pc
);
1072 /* Check syntax (end of line) */
1075 fprintf(stderr
, "%s line %d: error: additional tokens after ')'\n", pszSourceFileName
, nLine
);
1079 /* Don't relay-trace forwarded functions */
1080 exp
.uFlags
|= FL_NORELAY
;
1084 exp
.strTarget
.buf
= NULL
;
1085 exp
.strTarget
.len
= 0;
1088 /* Check for no-name without ordinal */
1089 if ((exp
.uFlags
& FL_ORDINAL
) && (exp
.nOrdinal
== -1))
1091 fprintf(stderr
, "%s line %d: error: ordinal export without ordinal!\n", pszSourceFileName
, nLine
);
1096 * Check for special handling of OLE exports, only when MSVC
1097 * is not used, since otherwise this is handled by MS LINK.EXE.
1101 /* Check whether the current export is not PRIVATE, or has an ordinal */
1102 int bIsNotPrivate
= (!gbNotPrivateNoWarn
&& /*gbImportLib &&*/ !(exp
.uFlags
& FL_PRIVATE
));
1103 int bHasOrdinal
= (exp
.uFlags
& FL_ORDINAL
);
1105 /* Check whether the current export is an OLE export, in case any of these tests pass */
1106 if (bIsNotPrivate
|| bHasOrdinal
)
1108 for (i
= 0; i
< ARRAYSIZE(astrOlePrivateExports
); ++i
)
1110 if (strlen(astrOlePrivateExports
[i
]) == exp
.strName
.len
&&
1111 strncmp(exp
.strName
.buf
, astrOlePrivateExports
[i
], exp
.strName
.len
) == 0)
1113 /* The current export is an OLE export: display the corresponding warning */
1116 fprintf(stderr
, "%s line %d: warning: exported symbol '%.*s' should be PRIVATE\n",
1117 pszSourceFileName
, nLine
, exp
.strName
.len
, exp
.strName
.buf
);
1121 fprintf(stderr
, "%s line %d: warning: exported symbol '%.*s' should not be assigned an ordinal\n",
1122 pszSourceFileName
, nLine
, exp
.strName
.len
, exp
.strName
.buf
);
1130 OutputLine(fileDest
, &exp
);
1139 printf("syntax: spec2def [<options> ...] <spec file>\n"
1140 "Possible options:\n"
1141 " -h --help print this help screen\n"
1142 " -l=<file> generate an asm lib stub\n"
1143 " -d=<file> generate a def file\n"
1144 " -s=<file> generate a stub file\n"
1145 " --ms MSVC compatibility\n"
1146 " -n=<name> name of the dll\n"
1147 " --implib generate a def file for an import library\n"
1148 " --no-private-warnings suppress warnings about symbols that should be -private\n"
1149 " -a=<arch> set architecture to <arch> (i386, x86_64, arm)\n"
1150 " --with-tracing generate wine-like \"+relay\" trace trampolines (needs -s)\n");
1153 int main(int argc
, char *argv
[])
1156 char *pszSource
, *pszDefFileName
= NULL
, *pszStubFileName
= NULL
, *pszLibStubName
= NULL
;
1157 const char* pszVersionOption
= "--version=0x";
1158 char achDllName
[40];
1169 for (i
= 1; i
< argc
&& *argv
[i
] == '-'; i
++)
1171 if ((strcasecmp(argv
[i
], "--help") == 0) ||
1172 (strcasecmp(argv
[i
], "-h") == 0))
1177 else if (argv
[i
][1] == 'd' && argv
[i
][2] == '=')
1179 pszDefFileName
= argv
[i
] + 3;
1181 else if (argv
[i
][1] == 'l' && argv
[i
][2] == '=')
1183 pszLibStubName
= argv
[i
] + 3;
1185 else if (argv
[i
][1] == 's' && argv
[i
][2] == '=')
1187 pszStubFileName
= argv
[i
] + 3;
1189 else if (argv
[i
][1] == 'n' && argv
[i
][2] == '=')
1191 pszDllName
= argv
[i
] + 3;
1193 else if (strncasecmp(argv
[i
], pszVersionOption
, strlen(pszVersionOption
)) == 0)
1195 guOsVersion
= strtoul(argv
[i
] + strlen(pszVersionOption
), NULL
, 16);
1197 else if (strcasecmp(argv
[i
], "--implib") == 0)
1201 else if (strcasecmp(argv
[i
], "--ms") == 0)
1205 else if (strcasecmp(argv
[i
], "--no-private-warnings") == 0)
1207 gbNotPrivateNoWarn
= 1;
1209 else if (strcasecmp(argv
[i
], "--with-tracing") == 0)
1211 if (!pszStubFileName
)
1213 fprintf(stderr
, "Error: cannot use --with-tracing without -s option.\n");
1218 else if (argv
[i
][1] == 'a' && argv
[i
][2] == '=')
1220 pszArchString
= argv
[i
] + 3;
1224 fprintf(stderr
, "Unrecognized option: %s\n", argv
[i
]);
1229 if (strcasecmp(pszArchString
, "i386") == 0)
1232 gpszUnderscore
= "_";
1234 else if (strcasecmp(pszArchString
, "x86_64") == 0) giArch
= ARCH_AMD64
;
1235 else if (strcasecmp(pszArchString
, "ia64") == 0) giArch
= ARCH_IA64
;
1236 else if (strcasecmp(pszArchString
, "arm") == 0) giArch
= ARCH_ARM
;
1237 else if (strcasecmp(pszArchString
, "ppc") == 0) giArch
= ARCH_PPC
;
1239 if ((giArch
== ARCH_AMD64
) || (giArch
== ARCH_IA64
))
1241 pszArchString2
= "win64";
1244 pszArchString2
= "win32";
1246 /* Set a default dll name */
1252 p1
= strrchr(argv
[i
], '\\');
1253 if (!p1
) p1
= strrchr(argv
[i
], '/');
1254 p2
= p1
= p1
? p1
+ 1 : argv
[i
];
1256 /* walk up to '.' */
1257 while (*p2
!= '.' && *p2
!= 0) p2
++;
1259 if (len
>= sizeof(achDllName
) - 5)
1261 fprintf(stderr
, "name too long: %s\n", p1
);
1265 strncpy(achDllName
, p1
, len
);
1266 strncpy(achDllName
+ len
, ".dll", sizeof(achDllName
) - len
);
1267 pszDllName
= achDllName
;
1270 /* Open input file */
1271 pszSourceFileName
= argv
[i
];
1272 file
= fopen(pszSourceFileName
, "r");
1275 fprintf(stderr
, "error: could not open file %s\n", pszSourceFileName
);
1280 fseek(file
, 0, SEEK_END
);
1281 nFileSize
= ftell(file
);
1284 /* Allocate memory buffer */
1285 pszSource
= malloc(nFileSize
+ 1);
1292 /* Load input file into memory */
1293 nFileSize
= fread(pszSource
, 1, nFileSize
, file
);
1296 /* Zero terminate the source */
1297 pszSource
[nFileSize
] = '\0';
1301 /* Open output file */
1302 file
= fopen(pszDefFileName
, "w");
1305 fprintf(stderr
, "error: could not open output file %s\n", argv
[i
+ 1]);
1309 OutputHeader_def(file
, pszDllName
);
1310 result
= ParseFile(pszSource
, file
, OutputLine_def
);
1314 if (pszStubFileName
)
1316 /* Open output file */
1317 file
= fopen(pszStubFileName
, "w");
1320 fprintf(stderr
, "error: could not open output file %s\n", argv
[i
+ 1]);
1324 OutputHeader_stub(file
);
1325 result
= ParseFile(pszSource
, file
, OutputLine_stub
);
1331 /* Open output file */
1332 file
= fopen(pszLibStubName
, "w");
1335 fprintf(stderr
, "error: could not open output file %s\n", argv
[i
+ 1]);
1339 OutputHeader_asmstub(file
, pszDllName
);
1340 result
= ParseFile(pszSource
, file
, OutputLine_asmstub
);
1341 fprintf(file
, "\n END\n");