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
[] =
98 static const char* astrShouldBePrivate
[] =
102 "DllGetClassFactoryFromClassString",
103 "DllGetDocumentation",
107 "DllRegisterServerEx",
108 "DllRegisterServerExW",
110 "DllUnregisterServer",
111 "RasCustomDeleteEntryNotify",
119 IsSeparator(char chr
)
121 return ((chr
<= ',' && chr
!= '$' && chr
!= '#') ||
122 (chr
>= ':' && chr
< '?') );
126 CompareToken(const char *token
, const char *comparand
)
130 if (*token
!= *comparand
) return 0;
134 if (IsSeparator(comparand
[-1])) return 1;
135 if (!IsSeparator(*token
)) return 0;
140 ScanToken(const char *token
, char chr
)
142 while (!IsSeparator(*token
))
144 if (*token
== chr
) return token
;
155 if (pc
[0] == '\n' && pc
[1] == '\r') return pc
+ 2;
156 else if (pc
[0] == '\n') return pc
+ 1;
163 TokenLength(char *pc
)
167 while (!IsSeparator(*pc
++)) length
++;
176 while (!IsSeparator(*pc
)) pc
++;
178 /* Skip white spaces */
179 while (*pc
== ' ' || *pc
== '\t') pc
++;
181 /* Check for end of line */
182 if (*pc
== '\n' || *pc
== '\r' || *pc
== 0) return 0;
184 /* Check for comment */
185 if (*pc
== '#' || *pc
== ';') return 0;
191 OutputHeader_stub(FILE *file
)
193 fprintf(file
, "/* This file is autogenerated, do not edit. */\n\n"
194 "#include <stubs.h>\n");
198 fprintf(file
, "#include <wine/debug.h>\n");
199 fprintf(file
, "#include <inttypes.h>\n");
200 fprintf(file
, "WINE_DECLARE_DEBUG_CHANNEL(relay);\n");
207 OutputLine_stub(FILE *file
, EXPORT
*pexp
)
211 int bInPrototype
= 0;
213 if (pexp
->nCallingConvention
!= CC_STUB
&&
214 (pexp
->uFlags
& FL_STUB
) == 0)
216 /* Only relay trace stdcall C functions */
217 if (!gbTracing
|| (pexp
->nCallingConvention
!= CC_STDCALL
)
218 || (pexp
->uFlags
& FL_NORELAY
)
219 || (pexp
->strName
.buf
[0] == '?'))
226 /* Declare the "real" function */
229 fprintf(file
, "extern ");
235 if (pexp
->uFlags
& FL_REGISTER
)
237 /* FIXME: Not sure this is right */
238 fprintf(file
, "void ");
240 else if (pexp
->uFlags
& FL_RET64
)
242 fprintf(file
, "__int64 ");
246 fprintf(file
, "int ");
249 if ((giArch
== ARCH_X86
) &&
250 pexp
->nCallingConvention
== CC_STDCALL
)
252 fprintf(file
, "__stdcall ");
256 if (pexp
->strName
.buf
[0] == '?')
258 fprintf(file
, "stub_function%d(", pexp
->nNumber
);
262 if (!bRelay
|| bInPrototype
)
263 fprintf(file
, "%.*s(", pexp
->strName
.len
, pexp
->strName
.buf
);
265 fprintf(file
, "$relaytrace$%.*s(", pexp
->strName
.len
, pexp
->strName
.buf
);
268 for (i
= 0; i
< pexp
->nArgCount
; i
++)
270 if (i
!= 0) fprintf(file
, ", ");
271 switch (pexp
->anArgs
[i
])
273 case ARG_LONG
: fprintf(file
, "long"); break;
274 case ARG_PTR
: fprintf(file
, "void*"); break;
275 case ARG_STR
: fprintf(file
, "char*"); break;
276 case ARG_WSTR
: fprintf(file
, "wchar_t*"); break;
277 case ARG_DBL
: fprintf(file
, "double"); break;
278 case ARG_INT64
: fprintf(file
, "__int64"); break;
279 /* __int128 is not supported on x86, and int128 in spec files most often represents a GUID */
280 case ARG_INT128
: fprintf(file
, "GUID"); break;
281 case ARG_FLOAT
: fprintf(file
, "float"); break;
283 fprintf(file
, " a%d", i
);
288 fprintf(file
, ");\n\n");
290 } while (bInPrototype
--);
294 fprintf(file
, ")\n{\n\tDbgPrint(\"WARNING: calling stub %.*s(",
295 pexp
->strName
.len
, pexp
->strName
.buf
);
299 fprintf(file
, ")\n{\n");
300 if (pexp
->uFlags
& FL_REGISTER
)
302 /* No return value */
304 else if (pexp
->uFlags
& FL_RET64
)
306 fprintf(file
, "\t__int64 retval;\n");
310 fprintf(file
, "\tint retval;\n");
312 fprintf(file
, "\tif (TRACE_ON(relay))\n\t\tDPRINTF(\"%s: %.*s(",
313 pszDllName
, pexp
->strName
.len
, pexp
->strName
.buf
);
316 for (i
= 0; i
< pexp
->nArgCount
; i
++)
318 if (i
!= 0) fprintf(file
, ",");
319 switch (pexp
->anArgs
[i
])
321 case ARG_LONG
: fprintf(file
, "0x%%lx"); break;
322 case ARG_PTR
: fprintf(file
, "0x%%p"); break;
323 case ARG_STR
: fprintf(file
, "'%%s'"); break;
324 case ARG_WSTR
: fprintf(file
, "'%%ws'"); break;
325 case ARG_DBL
: fprintf(file
, "%%f"); break;
326 case ARG_INT64
: fprintf(file
, "%%\"PRIx64\""); break;
327 case ARG_INT128
: fprintf(file
, "'%%s'"); break;
328 case ARG_FLOAT
: fprintf(file
, "%%f"); break;
331 fprintf(file
, ")\\n\"");
333 for (i
= 0; i
< pexp
->nArgCount
; i
++)
336 switch (pexp
->anArgs
[i
])
338 case ARG_LONG
: fprintf(file
, "(long)a%d", i
); break;
339 case ARG_PTR
: fprintf(file
, "(void*)a%d", i
); break;
340 case ARG_STR
: fprintf(file
, "(char*)a%d", i
); break;
341 case ARG_WSTR
: fprintf(file
, "(wchar_t*)a%d", i
); break;
342 case ARG_DBL
: fprintf(file
, "(double)a%d", i
); break;
343 case ARG_INT64
: fprintf(file
, "(__int64)a%d", i
); break;
344 case ARG_INT128
: fprintf(file
, "wine_dbgstr_guid(&a%d)", i
); break;
345 case ARG_FLOAT
: fprintf(file
, "(float)a%d", i
); break;
348 fprintf(file
, ");\n");
350 if (pexp
->nCallingConvention
== CC_STUB
)
352 fprintf(file
, "\t__wine_spec_unimplemented_stub(\"%s\", __FUNCTION__);\n", pszDllName
);
356 if (pexp
->uFlags
& FL_REGISTER
)
362 fprintf(file
, "\tretval = ");
364 fprintf(file
, "%.*s(", pexp
->strName
.len
, pexp
->strName
.buf
);
366 for (i
= 0; i
< pexp
->nArgCount
; i
++)
368 if (i
!= 0) fprintf(file
, ", ");
369 fprintf(file
, "a%d", i
);
371 fprintf(file
, ");\n");
375 fprintf(file
, "\treturn 0;\n}\n\n");
376 else if ((pexp
->uFlags
& FL_REGISTER
) == 0)
378 if (pexp
->uFlags
& FL_RET64
)
380 fprintf(file
, "\tif (TRACE_ON(relay))\n\t\tDPRINTF(\"%s: %.*s: retval = %%\"PRIx64\"\\n\", retval);\n",
381 pszDllName
, pexp
->strName
.len
, pexp
->strName
.buf
);
385 fprintf(file
, "\tif (TRACE_ON(relay))\n\t\tDPRINTF(\"%s: %.*s: retval = 0x%%lx\\n\", retval);\n",
386 pszDllName
, pexp
->strName
.len
, pexp
->strName
.buf
);
388 fprintf(file
, "\treturn retval;\n}\n\n");
395 OutputHeader_asmstub(FILE *file
, char *libname
)
397 fprintf(file
, "; File generated automatically, do not edit! \n\n");
399 if (giArch
== ARCH_X86
)
401 fprintf(file
, ".586\n.model flat\n.code\n");
403 else if (giArch
== ARCH_AMD64
)
405 fprintf(file
, ".code\n");
407 else if (giArch
== ARCH_ARM
)
409 fprintf(file
, " AREA |.text|,ALIGN=2,CODE,READONLY\n\n");
414 Output_stublabel(FILE *fileDest
, char* pszSymbolName
)
416 if (giArch
== ARCH_ARM
)
419 "\tEXPORT |%s| [FUNC]\n|%s|\n",
426 "PUBLIC %s\n%s: nop\n",
433 OutputLine_asmstub(FILE *fileDest
, EXPORT
*pexp
)
435 char szNameBuffer
[128];
437 /* Handle autoname */
438 if (pexp
->strName
.len
== 1 && pexp
->strName
.buf
[0] == '@')
440 sprintf(szNameBuffer
, "%sordinal%d\n%sordinal%d: nop\n",
441 gpszUnderscore
, pexp
->nOrdinal
, gpszUnderscore
, pexp
->nOrdinal
);
443 else if (giArch
!= ARCH_X86
)
445 sprintf(szNameBuffer
, "_stub_%.*s",
446 pexp
->strName
.len
, pexp
->strName
.buf
);
448 else if (pexp
->nCallingConvention
== CC_STDCALL
)
450 sprintf(szNameBuffer
, "__stub_%.*s@%d",
451 pexp
->strName
.len
, pexp
->strName
.buf
, pexp
->nStackBytes
);
453 else if (pexp
->nCallingConvention
== CC_FASTCALL
)
455 sprintf(szNameBuffer
, "@_stub_%.*s@%d",
456 pexp
->strName
.len
, pexp
->strName
.buf
, pexp
->nStackBytes
);
458 else if ((pexp
->nCallingConvention
== CC_CDECL
) ||
459 (pexp
->nCallingConvention
== CC_THISCALL
) ||
460 (pexp
->nCallingConvention
== CC_EXTERN
) ||
461 (pexp
->nCallingConvention
== CC_STUB
))
463 sprintf(szNameBuffer
, "__stub_%.*s",
464 pexp
->strName
.len
, pexp
->strName
.buf
);
468 fprintf(stderr
, "Invalid calling convention");
472 Output_stublabel(fileDest
, szNameBuffer
);
478 OutputHeader_def(FILE *file
, char *libname
)
481 "; File generated automatically, do not edit!\n\n"
488 PrintName(FILE *fileDest
, EXPORT
*pexp
, PSTRING pstr
, int fDeco
)
490 const char *pcName
= pstr
->buf
;
491 int nNameLength
= pstr
->len
;
492 const char* pcDot
, *pcAt
;
494 /* Check for non-x86 first */
495 if (giArch
!= ARCH_X86
)
497 /* Does the string already have stdcall decoration? */
498 pcAt
= ScanToken(pcName
, '@');
499 if (pcAt
&& (pcAt
< (pcName
+ nNameLength
)) && (pcName
[0] == '_'))
501 /* Skip leading underscore and remove trailing decoration */
503 nNameLength
= pcAt
- pcName
;
506 /* Print the undecorated function name */
507 fprintf(fileDest
, "%.*s", nNameLength
, pcName
);
510 ((pexp
->nCallingConvention
== CC_STDCALL
) ||
511 (pexp
->nCallingConvention
== CC_FASTCALL
)))
513 /* Scan for a dll forwarding dot */
514 pcDot
= ScanToken(pcName
, '.');
517 /* First print the dll name, followed by a dot */
518 nNameLength
= pcDot
- pcName
;
519 fprintf(fileDest
, "%.*s.", nNameLength
, pcName
);
521 /* Now the actual function name */
523 nNameLength
= pexp
->strTarget
.len
- nNameLength
- 1;
526 /* Does the string already have decoration? */
527 pcAt
= ScanToken(pcName
, '@');
528 if (pcAt
&& (pcAt
< (pcName
+ nNameLength
)))
530 /* On GCC, we need to remove the leading stdcall underscore */
531 if (!gbMSComp
&& (pexp
->nCallingConvention
== CC_STDCALL
))
537 /* Print the already decorated function name */
538 fprintf(fileDest
, "%.*s", nNameLength
, pcName
);
542 /* Print the prefix, but skip it for (GCC && stdcall) */
543 if (gbMSComp
|| (pexp
->nCallingConvention
!= CC_STDCALL
))
545 fprintf(fileDest
, "%c", pexp
->nCallingConvention
== CC_FASTCALL
? '@' : '_');
548 /* Print the name with trailing decoration */
549 fprintf(fileDest
, "%.*s@%d", nNameLength
, pcName
, pexp
->nStackBytes
);
554 /* Print the undecorated function name */
555 fprintf(fileDest
, "%.*s", nNameLength
, pcName
);
560 OutputLine_def_MS(FILE *fileDest
, EXPORT
*pexp
)
562 PrintName(fileDest
, pexp
, &pexp
->strName
, 0);
566 /* Redirect to a stub function, to get the right decoration in the lib */
567 fprintf(fileDest
, "=_stub_%.*s", pexp
->strName
.len
, pexp
->strName
.buf
);
569 else if (pexp
->strTarget
.buf
)
571 if (pexp
->strName
.buf
[0] == '?')
573 //fprintf(stderr, "warning: ignoring C++ redirection %.*s -> %.*s\n",
574 // pexp->strName.len, pexp->strName.buf, pexp->strTarget.len, pexp->strTarget.buf);
578 fprintf(fileDest
, "=");
580 /* If the original name was decorated, use decoration in the forwarder as well */
581 if ((giArch
== ARCH_X86
) && ScanToken(pexp
->strName
.buf
, '@') &&
582 !ScanToken(pexp
->strTarget
.buf
, '@') &&
583 ((pexp
->nCallingConvention
== CC_STDCALL
) ||
584 (pexp
->nCallingConvention
== CC_FASTCALL
)) )
586 PrintName(fileDest
, pexp
, &pexp
->strTarget
, 1);
590 /* Write the undecorated redirection name */
591 fprintf(fileDest
, "%.*s", pexp
->strTarget
.len
, pexp
->strTarget
.buf
);
595 else if (((pexp
->uFlags
& FL_STUB
) || (pexp
->nCallingConvention
== CC_STUB
)) &&
596 (pexp
->strName
.buf
[0] == '?'))
598 /* C++ stubs are forwarded to C stubs */
599 fprintf(fileDest
, "=stub_function%d", pexp
->nNumber
);
601 else if (gbTracing
&& ((pexp
->uFlags
& FL_NORELAY
) == 0) && (pexp
->nCallingConvention
== CC_STDCALL
) &&
602 (pexp
->strName
.buf
[0] != '?'))
604 /* Redirect it to the relay-tracing trampoline */
605 fprintf(fileDest
, "=$relaytrace$%.*s", pexp
->strName
.len
, pexp
->strName
.buf
);
610 OutputLine_def_GCC(FILE *fileDest
, EXPORT
*pexp
)
613 /* Print the function name, with decoration for export libs */
614 PrintName(fileDest
, pexp
, &pexp
->strName
, gbImportLib
);
615 DbgPrint("Generating def line for '%.*s'\n", pexp
->strName
.len
, pexp
->strName
.buf
);
617 /* Check if this is a forwarded export */
618 if (pexp
->strTarget
.buf
)
620 int fIsExternal
= !!ScanToken(pexp
->strTarget
.buf
, '.');
621 DbgPrint("Got redirect '%.*s'\n", pexp
->strTarget
.len
, pexp
->strTarget
.buf
);
623 /* print the target name, don't decorate if it is external */
624 fprintf(fileDest
, "=");
625 PrintName(fileDest
, pexp
, &pexp
->strTarget
, !fIsExternal
);
627 else if (((pexp
->uFlags
& FL_STUB
) || (pexp
->nCallingConvention
== CC_STUB
)) &&
628 (pexp
->strName
.buf
[0] == '?'))
630 /* C++ stubs are forwarded to C stubs */
631 fprintf(fileDest
, "=stub_function%d", pexp
->nNumber
);
633 else if (gbTracing
&& ((pexp
->uFlags
& FL_NORELAY
) == 0) &&
634 (pexp
->nCallingConvention
== CC_STDCALL
) &&
635 (pexp
->strName
.buf
[0] != '?'))
637 /* Redirect it to the relay-tracing trampoline */
640 fprintf(fileDest
, "=");
641 sprintf(buf
, "$relaytrace$%.*s", pexp
->strName
.len
, pexp
->strName
.buf
);
643 strTarget
.len
= pexp
->strName
.len
+ 12;
644 PrintName(fileDest
, pexp
, &strTarget
, 1);
648 /* Special handling for stdcall and fastcall */
649 if ((giArch
== ARCH_X86
) &&
650 ((pexp
->nCallingConvention
== CC_STDCALL
) ||
651 (pexp
->nCallingConvention
== CC_FASTCALL
)))
653 /* Is this the import lib? */
656 /* Is the name in the spec file decorated? */
657 const char* pcDeco
= ScanToken(pexp
->strName
.buf
, '@');
658 if (pcDeco
&& (pcDeco
< pexp
->strName
.buf
+ pexp
->strName
.len
))
660 /* Write the name including the leading @ */
661 fprintf(fileDest
, "==%.*s", pexp
->strName
.len
, pexp
->strName
.buf
);
664 else if ((!pexp
->strTarget
.buf
) && !(bTracing
))
666 /* Write a forwarder to the actual decorated symbol */
667 fprintf(fileDest
, "=");
668 PrintName(fileDest
, pexp
, &pexp
->strName
, 1);
674 OutputLine_def(FILE *fileDest
, EXPORT
*pexp
)
676 DbgPrint("OutputLine_def: '%.*s'...\n", pexp
->strName
.len
, pexp
->strName
.buf
);
677 fprintf(fileDest
, " ");
680 OutputLine_def_MS(fileDest
, pexp
);
682 OutputLine_def_GCC(fileDest
, pexp
);
684 if (pexp
->uFlags
& FL_ORDINAL
)
686 fprintf(fileDest
, " @%d", pexp
->nOrdinal
);
689 if (pexp
->uFlags
& FL_NONAME
)
691 fprintf(fileDest
, " NONAME");
694 /* Either PRIVATE or DATA */
695 if (pexp
->uFlags
& FL_PRIVATE
)
697 fprintf(fileDest
, " PRIVATE");
699 else if (pexp
->nCallingConvention
== CC_EXTERN
)
701 fprintf(fileDest
, " DATA");
704 fprintf(fileDest
, "\n");
710 ParseFile(char* pcStart
, FILE *fileDest
, PFNOUTLINE OutputLine
)
715 int included
, version_included
;
719 //fprintf(stderr, "info: line %d, pcStart:'%.30s'\n", nLine, pcStart);
724 for (pcLine
= pcStart
; *pcLine
; pcLine
= NextLine(pcLine
), nLine
++)
732 /* Skip white spaces */
733 while (*pc
== ' ' || *pc
== '\t') pc
++;
735 /* Skip empty lines, stop at EOF */
736 if (*pc
== ';' || *pc
<= '#') continue;
737 if (*pc
== 0) return 0;
739 /* Now we should get either an ordinal or @ */
744 exp
.nOrdinal
= atol(pc
);
745 /* The import lib should contain the ordinal only if -ordinal was specified */
747 exp
.uFlags
|= FL_ORDINAL
;
750 /* Go to next token (type) */
751 if (!(pc
= NextToken(pc
)))
753 fprintf(stderr
, "%s line %d: error: unexpected end of line\n", pszSourceFileName
, nLine
);
757 //fprintf(stderr, "info: Token:'%.*s'\n", TokenLength(pc), pc);
759 /* Now we should get the type */
760 if (CompareToken(pc
, "stdcall"))
762 exp
.nCallingConvention
= CC_STDCALL
;
764 else if (CompareToken(pc
, "cdecl") ||
765 CompareToken(pc
, "varargs"))
767 exp
.nCallingConvention
= CC_CDECL
;
769 else if (CompareToken(pc
, "fastcall"))
771 exp
.nCallingConvention
= CC_FASTCALL
;
773 else if (CompareToken(pc
, "thiscall"))
775 exp
.nCallingConvention
= CC_THISCALL
;
777 else if (CompareToken(pc
, "extern"))
779 exp
.nCallingConvention
= CC_EXTERN
;
781 else if (CompareToken(pc
, "stub"))
783 exp
.nCallingConvention
= CC_STUB
;
787 fprintf(stderr
, "%s line %d: error: expected callconv, got '%.*s' %d\n",
788 pszSourceFileName
, nLine
, TokenLength(pc
), pc
, *pc
);
792 /* Go to next token (options or name) */
793 if (!(pc
= NextToken(pc
)))
795 fprintf(stderr
, "fail2\n");
801 version_included
= 1;
804 if (CompareToken(pc
, "-arch="))
806 /* Default to not included */
810 /* Look if we are included */
814 if (CompareToken(pc
, pszArchString
) ||
815 CompareToken(pc
, pszArchString2
))
820 /* Skip to next arch or end */
821 while (*pc
> ',') pc
++;
822 } while (*pc
== ',');
824 else if (CompareToken(pc
, "-i386"))
826 if (giArch
!= ARCH_X86
) included
= 0;
828 else if (CompareToken(pc
, "-version="))
830 /* Default to not included */
831 version_included
= 0;
834 /* Look if we are included */
837 unsigned version
, endversion
;
839 /* Optionally skip leading '0x' */
841 if ((pc
[0] == '0') && (pc
[1] == 'x')) pc
+= 2;
843 /* Now get the version number */
844 endversion
= version
= strtoul(pc
, &pc
, 16);
846 /* Check if it's a range */
852 else if (pc
[0] == '-')
854 /* Optionally skip leading '0x' */
856 if ((pc
[0] == '0') && (pc
[1] == 'x')) pc
+= 2;
857 endversion
= strtoul(pc
, &pc
, 16);
860 /* Check for degenerate range */
861 if (version
> endversion
)
863 fprintf(stderr
, "%s line %d: error: invalid version rangen\n", pszSourceFileName
, nLine
);
867 /* Now compare the range with our version */
868 if ((guOsVersion
>= version
) &&
869 (guOsVersion
<= endversion
))
871 version_included
= 1;
874 /* Skip to next arch or end */
875 while (*pc
> ',') pc
++;
877 } while (*pc
== ',');
879 else if (CompareToken(pc
, "-private"))
881 exp
.uFlags
|= FL_PRIVATE
;
883 else if (CompareToken(pc
, "-noname"))
885 exp
.uFlags
|= FL_ORDINAL
| FL_NONAME
;
887 else if (CompareToken(pc
, "-ordinal"))
889 exp
.uFlags
|= FL_ORDINAL
;
890 /* GCC doesn't automatically import by ordinal if an ordinal
891 * is found in the def file. Force it. */
892 if (gbImportLib
&& !gbMSComp
)
893 exp
.uFlags
|= FL_NONAME
;
895 else if (CompareToken(pc
, "-stub"))
897 exp
.uFlags
|= FL_STUB
;
899 else if (CompareToken(pc
, "-norelay"))
901 exp
.uFlags
|= FL_NORELAY
;
903 else if (CompareToken(pc
, "-ret64"))
905 exp
.uFlags
|= FL_RET64
;
907 else if (CompareToken(pc
, "-register"))
909 exp
.uFlags
|= FL_REGISTER
;
913 fprintf(stderr
, "info: ignored option: '%.*s'\n",
914 TokenLength(pc
), pc
);
917 /* Go to next token */
921 //fprintf(stderr, "info: Name:'%.10s'\n", pc);
923 /* If arch didn't match ours, skip this entry */
924 if (!included
|| !version_included
) continue;
927 exp
.strName
.buf
= pc
;
928 exp
.strName
.len
= TokenLength(pc
);
929 DbgPrint("Got name: '%.*s'\n", exp
.strName
.len
, exp
.strName
.buf
);
931 /* Check for autoname */
932 if ((exp
.strName
.len
== 1) && (exp
.strName
.buf
[0] == '@'))
934 sprintf(namebuffer
, "ordinal%d", exp
.nOrdinal
);
935 exp
.strName
.len
= strlen(namebuffer
);
936 exp
.strName
.buf
= namebuffer
;
937 exp
.uFlags
|= FL_ORDINAL
| FL_NONAME
;
940 /* Handle parameters */
942 if (exp
.nCallingConvention
!= CC_EXTERN
&&
943 exp
.nCallingConvention
!= CC_STUB
)
945 /* Go to next token */
946 if (!(pc
= NextToken(pc
)))
948 fprintf(stderr
, "%s line %d: error: expected token\n", pszSourceFileName
, nLine
);
955 fprintf(stderr
, "%s line %d: error: expected '('\n", pszSourceFileName
, nLine
);
959 /* Skip whitespaces */
960 while (*pc
== ' ' || *pc
== '\t') pc
++;
965 if (CompareToken(pc
, "long"))
967 exp
.nStackBytes
+= 4;
968 exp
.anArgs
[exp
.nArgCount
] = ARG_LONG
;
970 else if (CompareToken(pc
, "double"))
972 exp
.nStackBytes
+= 8;
973 exp
.anArgs
[exp
.nArgCount
] = ARG_DBL
;
975 else if (CompareToken(pc
, "ptr"))
977 exp
.nStackBytes
+= 4; // sizeof(void*) on x86
978 exp
.anArgs
[exp
.nArgCount
] = ARG_PTR
;
980 else if (CompareToken(pc
, "str"))
982 exp
.nStackBytes
+= 4; // sizeof(void*) on x86
983 exp
.anArgs
[exp
.nArgCount
] = ARG_STR
;
985 else if (CompareToken(pc
, "wstr"))
987 exp
.nStackBytes
+= 4; // sizeof(void*) on x86
988 exp
.anArgs
[exp
.nArgCount
] = ARG_WSTR
;
990 else if (CompareToken(pc
, "int64"))
992 exp
.nStackBytes
+= 8;
993 exp
.anArgs
[exp
.nArgCount
] = ARG_INT64
;
995 else if (CompareToken(pc
, "int128"))
997 exp
.nStackBytes
+= 16;
998 exp
.anArgs
[exp
.nArgCount
] = ARG_INT128
;
1000 else if (CompareToken(pc
, "float"))
1002 exp
.nStackBytes
+= 4;
1003 exp
.anArgs
[exp
.nArgCount
] = ARG_FLOAT
;
1006 fprintf(stderr
, "%s line %d: error: expected type, got: %.10s\n", pszSourceFileName
, nLine
, pc
);
1010 /* Go to next parameter */
1011 if (!(pc
= NextToken(pc
)))
1013 fprintf(stderr
, "fail5\n");
1021 fprintf(stderr
, "%s line %d: error: expected ')'\n", pszSourceFileName
, nLine
);
1026 /* Handle special stub cases */
1027 if (exp
.nCallingConvention
== CC_STUB
)
1029 /* Check for c++ mangled name */
1032 //printf("Found c++ mangled name...\n");
1037 /* Check for stdcall name */
1038 const char *p
= ScanToken(pc
, '@');
1039 if (p
&& (p
- pc
< exp
.strName
.len
))
1043 /* Truncate the name to before the @ */
1044 exp
.strName
.len
= (int)(p
- pc
);
1045 if (exp
.strName
.len
< 1)
1047 fprintf(stderr
, "%s line %d: error: unexpected @ found\n", pszSourceFileName
, nLine
);
1050 exp
.nStackBytes
= atoi(p
+ 1);
1051 exp
.nArgCount
= exp
.nStackBytes
/ 4;
1052 exp
.nCallingConvention
= CC_STDCALL
;
1053 exp
.uFlags
|= FL_STUB
;
1054 for (i
= 0; i
< exp
.nArgCount
; i
++)
1055 exp
.anArgs
[i
] = ARG_LONG
;
1060 /* Get optional redirection */
1064 exp
.strTarget
.buf
= pc
;
1065 exp
.strTarget
.len
= TokenLength(pc
);
1067 /* Check syntax (end of line) */
1070 fprintf(stderr
, "%s line %d: error: additional tokens after ')'\n", pszSourceFileName
, nLine
);
1074 /* Don't relay-trace forwarded functions */
1075 exp
.uFlags
|= FL_NORELAY
;
1079 exp
.strTarget
.buf
= NULL
;
1080 exp
.strTarget
.len
= 0;
1083 /* Check for no-name without ordinal */
1084 if ((exp
.uFlags
& FL_ORDINAL
) && (exp
.nOrdinal
== -1))
1086 fprintf(stderr
, "%s line %d: error: ordinal export without ordinal!\n", pszSourceFileName
, nLine
);
1090 if (!gbMSComp
&& !gbNotPrivateNoWarn
&& gbImportLib
&& !(exp
.uFlags
& FL_PRIVATE
))
1092 for (i
= 0; i
< ARRAYSIZE(astrShouldBePrivate
); i
++)
1094 if (strlen(astrShouldBePrivate
[i
]) == exp
.strName
.len
&&
1095 strncmp(exp
.strName
.buf
, astrShouldBePrivate
[i
], exp
.strName
.len
) == 0)
1097 fprintf(stderr
, "%s line %d: warning: export of '%.*s' should be PRIVATE\n",
1098 pszSourceFileName
, nLine
, exp
.strName
.len
, exp
.strName
.buf
);
1103 OutputLine(fileDest
, &exp
);
1112 printf("syntax: spec2def [<options> ...] <spec file>\n"
1113 "Possible options:\n"
1114 " -h --help print this help screen\n"
1115 " -l=<file> generate an asm lib stub\n"
1116 " -d=<file> generate a def file\n"
1117 " -s=<file> generate a stub file\n"
1118 " --ms MSVC compatibility\n"
1119 " -n=<name> name of the dll\n"
1120 " --implib generate a def file for an import library\n"
1121 " --no-private-warnings suppress warnings about symbols that should be -private\n"
1122 " -a=<arch> set architecture to <arch> (i386, x86_64, arm)\n"
1123 " --with-tracing generate wine-like \"+relay\" trace trampolines (needs -s)\n");
1126 int main(int argc
, char *argv
[])
1129 char *pszSource
, *pszDefFileName
= NULL
, *pszStubFileName
= NULL
, *pszLibStubName
= NULL
;
1130 const char* pszVersionOption
= "--version=0x";
1131 char achDllName
[40];
1142 for (i
= 1; i
< argc
&& *argv
[i
] == '-'; i
++)
1144 if ((strcasecmp(argv
[i
], "--help") == 0) ||
1145 (strcasecmp(argv
[i
], "-h") == 0))
1150 else if (argv
[i
][1] == 'd' && argv
[i
][2] == '=')
1152 pszDefFileName
= argv
[i
] + 3;
1154 else if (argv
[i
][1] == 'l' && argv
[i
][2] == '=')
1156 pszLibStubName
= argv
[i
] + 3;
1158 else if (argv
[i
][1] == 's' && argv
[i
][2] == '=')
1160 pszStubFileName
= argv
[i
] + 3;
1162 else if (argv
[i
][1] == 'n' && argv
[i
][2] == '=')
1164 pszDllName
= argv
[i
] + 3;
1166 else if (strncasecmp(argv
[i
], pszVersionOption
, strlen(pszVersionOption
)) == 0)
1168 guOsVersion
= strtoul(argv
[i
] + strlen(pszVersionOption
), NULL
, 16);
1170 else if (strcasecmp(argv
[i
], "--implib") == 0)
1174 else if (strcasecmp(argv
[i
], "--ms") == 0)
1178 else if (strcasecmp(argv
[i
], "--no-private-warnings") == 0)
1180 gbNotPrivateNoWarn
= 1;
1182 else if (strcasecmp(argv
[i
], "--with-tracing") == 0)
1184 if (!pszStubFileName
)
1186 fprintf(stderr
, "Error: cannot use --with-tracing without -s option.\n");
1191 else if (argv
[i
][1] == 'a' && argv
[i
][2] == '=')
1193 pszArchString
= argv
[i
] + 3;
1197 fprintf(stderr
, "Unrecognized option: %s\n", argv
[i
]);
1202 if (strcasecmp(pszArchString
, "i386") == 0)
1205 gpszUnderscore
= "_";
1207 else if (strcasecmp(pszArchString
, "x86_64") == 0) giArch
= ARCH_AMD64
;
1208 else if (strcasecmp(pszArchString
, "ia64") == 0) giArch
= ARCH_IA64
;
1209 else if (strcasecmp(pszArchString
, "arm") == 0) giArch
= ARCH_ARM
;
1210 else if (strcasecmp(pszArchString
, "ppc") == 0) giArch
= ARCH_PPC
;
1212 if ((giArch
== ARCH_AMD64
) || (giArch
== ARCH_IA64
))
1214 pszArchString2
= "win64";
1217 pszArchString2
= "win32";
1219 /* Set a default dll name */
1225 p1
= strrchr(argv
[i
], '\\');
1226 if (!p1
) p1
= strrchr(argv
[i
], '/');
1227 p2
= p1
= p1
? p1
+ 1 : argv
[i
];
1229 /* walk up to '.' */
1230 while (*p2
!= '.' && *p2
!= 0) p2
++;
1232 if (len
>= sizeof(achDllName
) - 5)
1234 fprintf(stderr
, "name too long: %s\n", p1
);
1238 strncpy(achDllName
, p1
, len
);
1239 strncpy(achDllName
+ len
, ".dll", sizeof(achDllName
) - len
);
1240 pszDllName
= achDllName
;
1243 /* Open input file */
1244 pszSourceFileName
= argv
[i
];
1245 file
= fopen(pszSourceFileName
, "r");
1248 fprintf(stderr
, "error: could not open file %s\n", pszSourceFileName
);
1253 fseek(file
, 0, SEEK_END
);
1254 nFileSize
= ftell(file
);
1257 /* Allocate memory buffer */
1258 pszSource
= malloc(nFileSize
+ 1);
1265 /* Load input file into memory */
1266 nFileSize
= fread(pszSource
, 1, nFileSize
, file
);
1269 /* Zero terminate the source */
1270 pszSource
[nFileSize
] = '\0';
1274 /* Open output file */
1275 file
= fopen(pszDefFileName
, "w");
1278 fprintf(stderr
, "error: could not open output file %s\n", argv
[i
+ 1]);
1282 OutputHeader_def(file
, pszDllName
);
1283 result
= ParseFile(pszSource
, file
, OutputLine_def
);
1287 if (pszStubFileName
)
1289 /* Open output file */
1290 file
= fopen(pszStubFileName
, "w");
1293 fprintf(stderr
, "error: could not open output file %s\n", argv
[i
+ 1]);
1297 OutputHeader_stub(file
);
1298 result
= ParseFile(pszSource
, file
, OutputLine_stub
);
1304 /* Open output file */
1305 file
= fopen(pszLibStubName
, "w");
1308 fprintf(stderr
, "error: could not open output file %s\n", argv
[i
+ 1]);
1312 OutputHeader_asmstub(file
, pszDllName
);
1313 result
= ParseFile(pszSource
, file
, OutputLine_asmstub
);
1314 fprintf(file
, "\n END\n");