f1b5d78c28b2e7290df0e8492741cef43fea049b
8 #define strcasecmp(_String1, _String2) _stricmp(_String1, _String2)
9 #define strncasecmp(_String1, _String2, _MaxCount) _strnicmp(_String1, _String2, _MaxCount)
12 #define ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0]))
14 typedef struct _STRING
24 int nCallingConvention
;
42 typedef int (*PFNOUTLINE
)(FILE *, EXPORT
*);
45 int gbNotPrivateNoWarn
= 0;
47 int giArch
= ARCH_X86
;
48 char *pszArchString
= "i386";
50 char *pszSourceFileName
= NULL
;
51 char *pszDllName
= NULL
;
52 char *gpszUnderscore
= "";
54 unsigned guOsVersion
= 0x502;
55 #define DbgPrint(...) (!gbDebug || fprintf(stderr, __VA_ARGS__))
90 const char* astrCallingConventions
[] =
100 * List of OLE exports that should be PRIVATE and not be assigned an ordinal.
101 * In case these conditions are not met when linking with MS LINK.EXE, warnings
102 * LNK4104 and LNK4222 respectively are emitted.
104 static const char* astrOlePrivateExports
[] =
108 "DllGetClassFactoryFromClassString",
109 "DllGetDocumentation",
113 "DllRegisterServerEx",
114 "DllRegisterServerExW",
116 "DllUnregisterServer",
117 "RasCustomDeleteEntryNotify",
125 IsSeparator(char chr
)
127 return ((chr
<= ',' && chr
!= '$' && chr
!= '#') ||
128 (chr
>= ':' && chr
< '?') );
132 CompareToken(const char *token
, const char *comparand
)
136 if (*token
!= *comparand
) return 0;
140 if (IsSeparator(comparand
[-1])) return 1;
141 if (!IsSeparator(*token
)) return 0;
146 ScanToken(const char *token
, char chr
)
148 while (!IsSeparator(*token
))
150 if (*token
== chr
) return token
;
161 if (pc
[0] == '\n' && pc
[1] == '\r') return pc
+ 2;
162 else if (pc
[0] == '\n') return pc
+ 1;
169 TokenLength(char *pc
)
173 while (!IsSeparator(*pc
++)) length
++;
182 while (!IsSeparator(*pc
)) pc
++;
184 /* Skip white spaces */
185 while (*pc
== ' ' || *pc
== '\t') pc
++;
187 /* Check for end of line */
188 if (*pc
== '\n' || *pc
== '\r' || *pc
== 0) return 0;
190 /* Check for comment */
191 if (*pc
== '#' || *pc
== ';') return 0;
197 OutputHeader_stub(FILE *file
)
199 fprintf(file
, "/* This file is autogenerated, do not edit. */\n\n"
200 "#include <stubs.h>\n");
204 fprintf(file
, "#include <wine/debug.h>\n");
205 fprintf(file
, "#include <inttypes.h>\n");
206 fprintf(file
, "WINE_DECLARE_DEBUG_CHANNEL(relay);\n");
213 OutputLine_stub(FILE *file
, EXPORT
*pexp
)
217 int bInPrototype
= 0;
219 if (pexp
->nCallingConvention
!= CC_STUB
&&
220 (pexp
->uFlags
& FL_STUB
) == 0)
222 /* Only relay trace stdcall C functions */
223 if (!gbTracing
|| (pexp
->nCallingConvention
!= CC_STDCALL
)
224 || (pexp
->uFlags
& FL_NORELAY
)
225 || (pexp
->strName
.buf
[0] == '?'))
232 /* Declare the "real" function */
235 fprintf(file
, "extern ");
241 if (pexp
->uFlags
& FL_REGISTER
)
243 /* FIXME: Not sure this is right */
244 fprintf(file
, "void ");
246 else if (pexp
->uFlags
& FL_RET64
)
248 fprintf(file
, "__int64 ");
252 fprintf(file
, "int ");
255 if ((giArch
== ARCH_X86
) &&
256 pexp
->nCallingConvention
== CC_STDCALL
)
258 fprintf(file
, "__stdcall ");
262 if (pexp
->strName
.buf
[0] == '?')
264 fprintf(file
, "stub_function%d(", pexp
->nNumber
);
268 if (!bRelay
|| bInPrototype
)
269 fprintf(file
, "%.*s(", pexp
->strName
.len
, pexp
->strName
.buf
);
271 fprintf(file
, "$relaytrace$%.*s(", pexp
->strName
.len
, pexp
->strName
.buf
);
274 for (i
= 0; i
< pexp
->nArgCount
; i
++)
276 if (i
!= 0) fprintf(file
, ", ");
277 switch (pexp
->anArgs
[i
])
279 case ARG_LONG
: fprintf(file
, "long"); break;
280 case ARG_PTR
: fprintf(file
, "void*"); break;
281 case ARG_STR
: fprintf(file
, "char*"); break;
282 case ARG_WSTR
: fprintf(file
, "wchar_t*"); break;
283 case ARG_DBL
: fprintf(file
, "double"); break;
284 case ARG_INT64
: fprintf(file
, "__int64"); break;
285 /* __int128 is not supported on x86, and int128 in spec files most often represents a GUID */
286 case ARG_INT128
: fprintf(file
, "GUID"); break;
287 case ARG_FLOAT
: fprintf(file
, "float"); break;
289 fprintf(file
, " a%d", i
);
294 fprintf(file
, ");\n\n");
296 } while (bInPrototype
--);
300 fprintf(file
, ")\n{\n\tDbgPrint(\"WARNING: calling stub %.*s(",
301 pexp
->strName
.len
, pexp
->strName
.buf
);
305 fprintf(file
, ")\n{\n");
306 if (pexp
->uFlags
& FL_REGISTER
)
308 /* No return value */
310 else if (pexp
->uFlags
& FL_RET64
)
312 fprintf(file
, "\t__int64 retval;\n");
316 fprintf(file
, "\tint retval;\n");
318 fprintf(file
, "\tif (TRACE_ON(relay))\n\t\tDPRINTF(\"%s: %.*s(",
319 pszDllName
, pexp
->strName
.len
, pexp
->strName
.buf
);
322 for (i
= 0; i
< pexp
->nArgCount
; i
++)
324 if (i
!= 0) fprintf(file
, ",");
325 switch (pexp
->anArgs
[i
])
327 case ARG_LONG
: fprintf(file
, "0x%%lx"); break;
328 case ARG_PTR
: fprintf(file
, "0x%%p"); break;
329 case ARG_STR
: fprintf(file
, "'%%s'"); break;
330 case ARG_WSTR
: fprintf(file
, "'%%ws'"); break;
331 case ARG_DBL
: fprintf(file
, "%%f"); break;
332 case ARG_INT64
: fprintf(file
, "%%\"PRIx64\""); break;
333 case ARG_INT128
: fprintf(file
, "'%%s'"); break;
334 case ARG_FLOAT
: fprintf(file
, "%%f"); break;
337 fprintf(file
, ")\\n\"");
339 for (i
= 0; i
< pexp
->nArgCount
; i
++)
342 switch (pexp
->anArgs
[i
])
344 case ARG_LONG
: fprintf(file
, "(long)a%d", i
); break;
345 case ARG_PTR
: fprintf(file
, "(void*)a%d", i
); break;
346 case ARG_STR
: fprintf(file
, "(char*)a%d", i
); break;
347 case ARG_WSTR
: fprintf(file
, "(wchar_t*)a%d", i
); break;
348 case ARG_DBL
: fprintf(file
, "(double)a%d", i
); break;
349 case ARG_INT64
: fprintf(file
, "(__int64)a%d", i
); break;
350 case ARG_INT128
: fprintf(file
, "wine_dbgstr_guid(&a%d)", i
); break;
351 case ARG_FLOAT
: fprintf(file
, "(float)a%d", i
); break;
354 fprintf(file
, ");\n");
356 if (pexp
->nCallingConvention
== CC_STUB
)
358 fprintf(file
, "\t__wine_spec_unimplemented_stub(\"%s\", __FUNCTION__);\n", pszDllName
);
362 if (pexp
->uFlags
& FL_REGISTER
)
368 fprintf(file
, "\tretval = ");
370 fprintf(file
, "%.*s(", pexp
->strName
.len
, pexp
->strName
.buf
);
372 for (i
= 0; i
< pexp
->nArgCount
; i
++)
374 if (i
!= 0) fprintf(file
, ", ");
375 fprintf(file
, "a%d", i
);
377 fprintf(file
, ");\n");
381 fprintf(file
, "\treturn 0;\n}\n\n");
382 else if ((pexp
->uFlags
& FL_REGISTER
) == 0)
384 if (pexp
->uFlags
& FL_RET64
)
386 fprintf(file
, "\tif (TRACE_ON(relay))\n\t\tDPRINTF(\"%s: %.*s: retval = %%\"PRIx64\"\\n\", retval);\n",
387 pszDllName
, pexp
->strName
.len
, pexp
->strName
.buf
);
391 fprintf(file
, "\tif (TRACE_ON(relay))\n\t\tDPRINTF(\"%s: %.*s: retval = 0x%%lx\\n\", retval);\n",
392 pszDllName
, pexp
->strName
.len
, pexp
->strName
.buf
);
394 fprintf(file
, "\treturn retval;\n}\n\n");
401 OutputHeader_asmstub(FILE *file
, char *libname
)
403 fprintf(file
, "; File generated automatically, do not edit! \n\n");
405 if (giArch
== ARCH_X86
)
407 fprintf(file
, ".586\n.model flat\n.code\n");
409 else if (giArch
== ARCH_AMD64
)
411 fprintf(file
, ".code\n");
413 else if (giArch
== ARCH_ARM
)
415 fprintf(file
, " AREA |.text|,ALIGN=2,CODE,READONLY\n\n");
420 Output_stublabel(FILE *fileDest
, char* pszSymbolName
)
422 if (giArch
== ARCH_ARM
)
425 "\tEXPORT |%s| [FUNC]\n|%s|\n",
432 "PUBLIC %s\n%s: nop\n",
439 OutputLine_asmstub(FILE *fileDest
, EXPORT
*pexp
)
441 char szNameBuffer
[128];
443 /* Handle autoname */
444 if (pexp
->strName
.len
== 1 && pexp
->strName
.buf
[0] == '@')
446 sprintf(szNameBuffer
, "%sordinal%d\n%sordinal%d: nop\n",
447 gpszUnderscore
, pexp
->nOrdinal
, gpszUnderscore
, pexp
->nOrdinal
);
449 else if (giArch
!= ARCH_X86
)
451 sprintf(szNameBuffer
, "_stub_%.*s",
452 pexp
->strName
.len
, pexp
->strName
.buf
);
454 else if (pexp
->nCallingConvention
== CC_STDCALL
)
456 sprintf(szNameBuffer
, "__stub_%.*s@%d",
457 pexp
->strName
.len
, pexp
->strName
.buf
, pexp
->nStackBytes
);
459 else if (pexp
->nCallingConvention
== CC_FASTCALL
)
461 sprintf(szNameBuffer
, "@_stub_%.*s@%d",
462 pexp
->strName
.len
, pexp
->strName
.buf
, pexp
->nStackBytes
);
464 else if ((pexp
->nCallingConvention
== CC_CDECL
) ||
465 (pexp
->nCallingConvention
== CC_THISCALL
) ||
466 (pexp
->nCallingConvention
== CC_EXTERN
) ||
467 (pexp
->nCallingConvention
== CC_STUB
))
469 sprintf(szNameBuffer
, "__stub_%.*s",
470 pexp
->strName
.len
, pexp
->strName
.buf
);
474 fprintf(stderr
, "Invalid calling convention");
478 Output_stublabel(fileDest
, szNameBuffer
);
484 OutputHeader_def(FILE *file
, char *libname
)
487 "; File generated automatically, do not edit!\n\n"
494 PrintName(FILE *fileDest
, EXPORT
*pexp
, PSTRING pstr
, int fDeco
)
496 const char *pcName
= pstr
->buf
;
497 int nNameLength
= pstr
->len
;
498 const char* pcDot
, *pcAt
;
500 /* Check for non-x86 first */
501 if (giArch
!= ARCH_X86
)
503 /* Does the string already have stdcall decoration? */
504 pcAt
= ScanToken(pcName
, '@');
505 if (pcAt
&& (pcAt
< (pcName
+ nNameLength
)) && (pcName
[0] == '_'))
507 /* Skip leading underscore and remove trailing decoration */
509 nNameLength
= (int)(pcAt
- pcName
);
512 /* Print the undecorated function name */
513 fprintf(fileDest
, "%.*s", nNameLength
, pcName
);
516 ((pexp
->nCallingConvention
== CC_STDCALL
) ||
517 (pexp
->nCallingConvention
== CC_FASTCALL
)))
519 /* Scan for a dll forwarding dot */
520 pcDot
= ScanToken(pcName
, '.');
523 /* First print the dll name, followed by a dot */
524 nNameLength
= (int)(pcDot
- pcName
);
525 fprintf(fileDest
, "%.*s.", nNameLength
, pcName
);
527 /* Now the actual function name */
529 nNameLength
= pexp
->strTarget
.len
- nNameLength
- 1;
532 /* Does the string already have decoration? */
533 pcAt
= ScanToken(pcName
, '@');
534 if (pcAt
&& (pcAt
< (pcName
+ nNameLength
)))
536 /* On GCC, we need to remove the leading stdcall underscore */
537 if (!gbMSComp
&& (pexp
->nCallingConvention
== CC_STDCALL
))
543 /* Print the already decorated function name */
544 fprintf(fileDest
, "%.*s", nNameLength
, pcName
);
548 /* Print the prefix, but skip it for (GCC && stdcall) */
549 if (gbMSComp
|| (pexp
->nCallingConvention
!= CC_STDCALL
))
551 fprintf(fileDest
, "%c", pexp
->nCallingConvention
== CC_FASTCALL
? '@' : '_');
554 /* Print the name with trailing decoration */
555 fprintf(fileDest
, "%.*s@%d", nNameLength
, pcName
, pexp
->nStackBytes
);
560 /* Print the undecorated function name */
561 fprintf(fileDest
, "%.*s", nNameLength
, pcName
);
566 OutputLine_def_MS(FILE *fileDest
, EXPORT
*pexp
)
568 PrintName(fileDest
, pexp
, &pexp
->strName
, 0);
572 /* Redirect to a stub function, to get the right decoration in the lib */
573 fprintf(fileDest
, "=_stub_%.*s", pexp
->strName
.len
, pexp
->strName
.buf
);
575 else if (pexp
->strTarget
.buf
)
577 if (pexp
->strName
.buf
[0] == '?')
579 //fprintf(stderr, "warning: ignoring C++ redirection %.*s -> %.*s\n",
580 // pexp->strName.len, pexp->strName.buf, pexp->strTarget.len, pexp->strTarget.buf);
584 fprintf(fileDest
, "=");
586 /* If the original name was decorated, use decoration in the forwarder as well */
587 if ((giArch
== ARCH_X86
) && ScanToken(pexp
->strName
.buf
, '@') &&
588 !ScanToken(pexp
->strTarget
.buf
, '@') &&
589 ((pexp
->nCallingConvention
== CC_STDCALL
) ||
590 (pexp
->nCallingConvention
== CC_FASTCALL
)) )
592 PrintName(fileDest
, pexp
, &pexp
->strTarget
, 1);
596 /* Write the undecorated redirection name */
597 fprintf(fileDest
, "%.*s", pexp
->strTarget
.len
, pexp
->strTarget
.buf
);
601 else if (((pexp
->uFlags
& FL_STUB
) || (pexp
->nCallingConvention
== CC_STUB
)) &&
602 (pexp
->strName
.buf
[0] == '?'))
604 /* C++ stubs are forwarded to C stubs */
605 fprintf(fileDest
, "=stub_function%d", pexp
->nNumber
);
607 else if (gbTracing
&& ((pexp
->uFlags
& FL_NORELAY
) == 0) && (pexp
->nCallingConvention
== CC_STDCALL
) &&
608 (pexp
->strName
.buf
[0] != '?'))
610 /* Redirect it to the relay-tracing trampoline */
611 fprintf(fileDest
, "=$relaytrace$%.*s", pexp
->strName
.len
, pexp
->strName
.buf
);
616 OutputLine_def_GCC(FILE *fileDest
, EXPORT
*pexp
)
619 /* Print the function name, with decoration for export libs */
620 PrintName(fileDest
, pexp
, &pexp
->strName
, gbImportLib
);
621 DbgPrint("Generating def line for '%.*s'\n", pexp
->strName
.len
, pexp
->strName
.buf
);
623 /* Check if this is a forwarded export */
624 if (pexp
->strTarget
.buf
)
626 int fIsExternal
= !!ScanToken(pexp
->strTarget
.buf
, '.');
627 DbgPrint("Got redirect '%.*s'\n", pexp
->strTarget
.len
, pexp
->strTarget
.buf
);
629 /* print the target name, don't decorate if it is external */
630 fprintf(fileDest
, "=");
631 PrintName(fileDest
, pexp
, &pexp
->strTarget
, !fIsExternal
);
633 else if (((pexp
->uFlags
& FL_STUB
) || (pexp
->nCallingConvention
== CC_STUB
)) &&
634 (pexp
->strName
.buf
[0] == '?'))
636 /* C++ stubs are forwarded to C stubs */
637 fprintf(fileDest
, "=stub_function%d", pexp
->nNumber
);
639 else if (gbTracing
&& ((pexp
->uFlags
& FL_NORELAY
) == 0) &&
640 (pexp
->nCallingConvention
== CC_STDCALL
) &&
641 (pexp
->strName
.buf
[0] != '?'))
643 /* Redirect it to the relay-tracing trampoline */
646 fprintf(fileDest
, "=");
647 sprintf(buf
, "$relaytrace$%.*s", pexp
->strName
.len
, pexp
->strName
.buf
);
649 strTarget
.len
= pexp
->strName
.len
+ 12;
650 PrintName(fileDest
, pexp
, &strTarget
, 1);
654 /* Special handling for stdcall and fastcall */
655 if ((giArch
== ARCH_X86
) &&
656 ((pexp
->nCallingConvention
== CC_STDCALL
) ||
657 (pexp
->nCallingConvention
== CC_FASTCALL
)))
659 /* Is this the import lib? */
662 /* Is the name in the spec file decorated? */
663 const char* pcDeco
= ScanToken(pexp
->strName
.buf
, '@');
664 if (pcDeco
&& (pcDeco
< pexp
->strName
.buf
+ pexp
->strName
.len
))
666 /* Write the name including the leading @ */
667 fprintf(fileDest
, "==%.*s", pexp
->strName
.len
, pexp
->strName
.buf
);
670 else if ((!pexp
->strTarget
.buf
) && !(bTracing
))
672 /* Write a forwarder to the actual decorated symbol */
673 fprintf(fileDest
, "=");
674 PrintName(fileDest
, pexp
, &pexp
->strName
, 1);
680 OutputLine_def(FILE *fileDest
, EXPORT
*pexp
)
682 DbgPrint("OutputLine_def: '%.*s'...\n", pexp
->strName
.len
, pexp
->strName
.buf
);
683 fprintf(fileDest
, " ");
686 OutputLine_def_MS(fileDest
, pexp
);
688 OutputLine_def_GCC(fileDest
, pexp
);
690 if (pexp
->uFlags
& FL_ORDINAL
)
692 fprintf(fileDest
, " @%d", pexp
->nOrdinal
);
695 if (pexp
->uFlags
& FL_NONAME
)
697 fprintf(fileDest
, " NONAME");
700 /* Either PRIVATE or DATA */
701 if (pexp
->uFlags
& FL_PRIVATE
)
703 fprintf(fileDest
, " PRIVATE");
705 else if (pexp
->nCallingConvention
== CC_EXTERN
)
707 fprintf(fileDest
, " DATA");
710 fprintf(fileDest
, "\n");
717 const char* filename
,
725 unsigned i
, errorpos
, len
;
726 const char* pcLineEnd
;
728 /* Get the length of the line */
729 pcLineEnd
= strpbrk(pcLine
, "\r\n");
730 len
= pcLineEnd
- pcLine
;
734 pc
= pcLine
+ len
- 1;
738 errorpos
= (unsigned)(pc
- pcLine
);
740 /* Output the error message */
741 fprintf(stderr
, "ERROR: (%s:%u:%u): ", filename
, nLine
, errorpos
);
742 vfprintf(stderr
, format
, argptr
);
743 fprintf(stderr
, "\n");
745 /* Output the line with the error */
746 fprintf(stderr
, "> %.*s\n", len
, pcLine
);
750 errorlen
= TokenLength(pc
);
753 for (i
= 0; i
< errorpos
+ 2; i
++)
755 fprintf(stderr
, " ");
757 for (i
= 0; i
< errorlen
; i
++)
759 fprintf(stderr
, "~");
761 fprintf(stderr
, "\n");
767 const char* filename
,
777 va_start(argptr
, format
);
778 Fatalv(filename
, nLine
, pcLine
, pc
, errorlen
, format
, argptr
);
783 ParseFile(char* pcStart
, FILE *fileDest
, PFNOUTLINE OutputLine
)
788 int included
, version_included
;
792 //fprintf(stderr, "info: line %d, pcStart:'%.30s'\n", nLine, pcStart);
797 for (pcLine
= pcStart
; *pcLine
; pcLine
= NextLine(pcLine
), nLine
++)
805 /* Skip white spaces */
806 while (*pc
== ' ' || *pc
== '\t') pc
++;
808 /* Skip empty lines, stop at EOF */
809 if (*pc
== ';' || *pc
<= '#') continue;
810 if (*pc
== 0) return 0;
812 /* Now we should get either an ordinal or @ */
817 else if ((*pc
>= '0') && (*pc
<= '9'))
820 long int number
= strtol(pc
, &end
, 10);
821 if ((*end
!= ' ') && (*end
!= '\t'))
823 Fatal(pszSourceFileName
, nLine
, pcLine
, end
, 0, "Unexpected character(s) after ordinal");
826 if ((number
< 0) || (number
> 0xFFFE))
828 Fatal(pszSourceFileName
, nLine
, pcLine
, pc
, 0, "Invalid value for ordinal");
831 exp
.nOrdinal
= number
;
833 /* The import lib should contain the ordinal only if -ordinal was specified */
835 exp
.uFlags
|= FL_ORDINAL
;
839 Fatal(pszSourceFileName
, nLine
, pcLine
, pc
, 0, "Expected '@' or ordinal");
842 /* Go to next token (type) */
843 if (!(pc
= NextToken(pc
)))
845 Fatal(pszSourceFileName
, nLine
, pcLine
, pc
, 1, "Unexpected end of line");
848 //fprintf(stderr, "info: Token:'%.*s'\n", TokenLength(pc), pc);
850 /* Now we should get the type */
851 if (CompareToken(pc
, "stdcall"))
853 exp
.nCallingConvention
= CC_STDCALL
;
855 else if (CompareToken(pc
, "cdecl") ||
856 CompareToken(pc
, "varargs"))
858 exp
.nCallingConvention
= CC_CDECL
;
860 else if (CompareToken(pc
, "fastcall"))
862 exp
.nCallingConvention
= CC_FASTCALL
;
864 else if (CompareToken(pc
, "thiscall"))
866 exp
.nCallingConvention
= CC_THISCALL
;
868 else if (CompareToken(pc
, "extern"))
870 exp
.nCallingConvention
= CC_EXTERN
;
872 else if (CompareToken(pc
, "stub"))
874 exp
.nCallingConvention
= CC_STUB
;
878 Fatal(pszSourceFileName
, nLine
, pcLine
, pc
, 0, "Invalid calling convention");
881 /* Go to next token (options or name) */
882 if (!(pc
= NextToken(pc
)))
884 Fatal(pszSourceFileName
, nLine
, pcLine
, pc
, 1, "Unexpected end of line");
889 version_included
= 1;
892 if (CompareToken(pc
, "-arch="))
894 /* Default to not included */
898 /* Look if we are included */
902 if (CompareToken(pc
, pszArchString
) ||
903 CompareToken(pc
, pszArchString2
))
908 /* Skip to next arch or end */
909 while (*pc
> ',') pc
++;
910 } while (*pc
== ',');
912 else if (CompareToken(pc
, "-i386"))
914 if (giArch
!= ARCH_X86
) included
= 0;
916 else if (CompareToken(pc
, "-version="))
918 char * pcVersionStart
= pc
+ 9;
920 /* Default to not included */
921 version_included
= 0;
924 /* Look if we are included */
927 unsigned version
, endversion
;
929 /* Optionally skip leading '0x' */
931 if ((pc
[0] == '0') && (pc
[1] == 'x')) pc
+= 2;
933 /* Now get the version number */
934 endversion
= version
= strtoul(pc
, &pc
, 16);
936 /* Check if it's a range */
942 else if (pc
[0] == '-')
944 /* Optionally skip leading '0x' */
946 if ((pc
[0] == '0') && (pc
[1] == 'x')) pc
+= 2;
947 endversion
= strtoul(pc
, &pc
, 16);
950 /* Check for degenerate range */
951 if (version
> endversion
)
953 Fatal(pszSourceFileName
,
958 "Invalid version range");
961 /* Now compare the range with our version */
962 if ((guOsVersion
>= version
) &&
963 (guOsVersion
<= endversion
))
965 version_included
= 1;
968 /* Skip to next arch or end */
969 while (*pc
> ',') pc
++;
971 } while (*pc
== ',');
973 else if (CompareToken(pc
, "-private"))
975 exp
.uFlags
|= FL_PRIVATE
;
977 else if (CompareToken(pc
, "-noname"))
979 exp
.uFlags
|= FL_ORDINAL
| FL_NONAME
;
981 else if (CompareToken(pc
, "-ordinal"))
983 exp
.uFlags
|= FL_ORDINAL
;
984 /* GCC doesn't automatically import by ordinal if an ordinal
985 * is found in the def file. Force it. */
986 if (gbImportLib
&& !gbMSComp
)
987 exp
.uFlags
|= FL_NONAME
;
989 else if (CompareToken(pc
, "-stub"))
991 exp
.uFlags
|= FL_STUB
;
993 else if (CompareToken(pc
, "-norelay"))
995 exp
.uFlags
|= FL_NORELAY
;
997 else if (CompareToken(pc
, "-ret64"))
999 exp
.uFlags
|= FL_RET64
;
1001 else if (CompareToken(pc
, "-register"))
1003 exp
.uFlags
|= FL_REGISTER
;
1008 "INFO: %s line %d: Ignored option: '%.*s'\n",
1015 /* Go to next token */
1019 //fprintf(stderr, "info: Name:'%.10s'\n", pc);
1021 /* If arch didn't match ours, skip this entry */
1022 if (!included
|| !version_included
) continue;
1025 exp
.strName
.buf
= pc
;
1026 exp
.strName
.len
= TokenLength(pc
);
1027 //DbgPrint("Got name: '%.*s'\n", exp.strName.len, exp.strName.buf);
1029 /* Check for autoname */
1030 if ((exp
.strName
.len
== 1) && (exp
.strName
.buf
[0] == '@'))
1032 sprintf(namebuffer
, "ordinal%d", exp
.nOrdinal
);
1033 exp
.strName
.len
= strlen(namebuffer
);
1034 exp
.strName
.buf
= namebuffer
;
1035 exp
.uFlags
|= FL_ORDINAL
| FL_NONAME
;
1038 /* Handle parameters */
1039 exp
.nStackBytes
= 0;
1040 if (exp
.nCallingConvention
!= CC_EXTERN
&&
1041 exp
.nCallingConvention
!= CC_STUB
)
1043 /* Go to next token */
1044 if (!(pc
= NextToken(pc
)))
1046 Fatal(pszSourceFileName
, nLine
, pcLine
, pc
, 1, "Unexpected end of line");
1052 Fatal(pszSourceFileName
, nLine
, pcLine
, pc
- 1, 0, "Expected '('");
1055 /* Skip whitespaces */
1056 while (*pc
== ' ' || *pc
== '\t') pc
++;
1058 exp
.nStackBytes
= 0;
1061 if (CompareToken(pc
, "long"))
1063 exp
.nStackBytes
+= 4;
1064 exp
.anArgs
[exp
.nArgCount
] = ARG_LONG
;
1066 else if (CompareToken(pc
, "double"))
1068 exp
.nStackBytes
+= 8;
1069 exp
.anArgs
[exp
.nArgCount
] = ARG_DBL
;
1071 else if (CompareToken(pc
, "ptr"))
1073 exp
.nStackBytes
+= 4; // sizeof(void*) on x86
1074 exp
.anArgs
[exp
.nArgCount
] = ARG_PTR
;
1076 else if (CompareToken(pc
, "str"))
1078 exp
.nStackBytes
+= 4; // sizeof(void*) on x86
1079 exp
.anArgs
[exp
.nArgCount
] = ARG_STR
;
1081 else if (CompareToken(pc
, "wstr"))
1083 exp
.nStackBytes
+= 4; // sizeof(void*) on x86
1084 exp
.anArgs
[exp
.nArgCount
] = ARG_WSTR
;
1086 else if (CompareToken(pc
, "int64"))
1088 exp
.nStackBytes
+= 8;
1089 exp
.anArgs
[exp
.nArgCount
] = ARG_INT64
;
1091 else if (CompareToken(pc
, "int128"))
1093 exp
.nStackBytes
+= 16;
1094 exp
.anArgs
[exp
.nArgCount
] = ARG_INT128
;
1096 else if (CompareToken(pc
, "float"))
1098 exp
.nStackBytes
+= 4;
1099 exp
.anArgs
[exp
.nArgCount
] = ARG_FLOAT
;
1103 Fatal(pszSourceFileName
, nLine
, pcLine
, pc
, 0, "Unrecognized type");
1108 /* Go to next parameter */
1109 if (!(pc
= NextToken(pc
)))
1111 Fatal(pszSourceFileName
, nLine
, pcLine
, pc
, 1, "Unexpected end of line");
1118 Fatal(pszSourceFileName
, nLine
, pcLine
, pc
- 1, 0, "Expected ')'");
1122 /* Handle special stub cases */
1123 if (exp
.nCallingConvention
== CC_STUB
)
1125 /* Check for c++ mangled name */
1128 //printf("Found c++ mangled name...\n");
1133 /* Check for stdcall name */
1134 const char *p
= ScanToken(pc
, '@');
1135 if (p
&& (p
- pc
< exp
.strName
.len
))
1139 /* Truncate the name to before the @ */
1140 exp
.strName
.len
= (int)(p
- pc
);
1141 if (exp
.strName
.len
< 1)
1143 Fatal(pszSourceFileName
, nLine
, pcLine
, p
, 1, "Unexpected @");
1145 exp
.nStackBytes
= atoi(p
+ 1);
1146 exp
.nArgCount
= exp
.nStackBytes
/ 4;
1147 exp
.nCallingConvention
= CC_STDCALL
;
1148 exp
.uFlags
|= FL_STUB
;
1149 for (i
= 0; i
< exp
.nArgCount
; i
++)
1150 exp
.anArgs
[i
] = ARG_LONG
;
1155 /* Get optional redirection */
1159 exp
.strTarget
.buf
= pc
;
1160 exp
.strTarget
.len
= TokenLength(pc
);
1162 /* Check syntax (end of line) */
1165 Fatal(pszSourceFileName
, nLine
, pcLine
, NextToken(pc
), 0, "Excess token(s) at end of definition");
1168 /* Don't relay-trace forwarded functions */
1169 exp
.uFlags
|= FL_NORELAY
;
1173 exp
.strTarget
.buf
= NULL
;
1174 exp
.strTarget
.len
= 0;
1177 /* Check for no-name without ordinal */
1178 if ((exp
.uFlags
& FL_ORDINAL
) && (exp
.nOrdinal
== -1))
1180 Fatal(pszSourceFileName
, nLine
, pcLine
, pc
, 0, "Ordinal export without ordinal");
1184 * Check for special handling of OLE exports, only when MSVC
1185 * is not used, since otherwise this is handled by MS LINK.EXE.
1189 /* Check whether the current export is not PRIVATE, or has an ordinal */
1190 int bIsNotPrivate
= (!gbNotPrivateNoWarn
&& /*gbImportLib &&*/ !(exp
.uFlags
& FL_PRIVATE
));
1191 int bHasOrdinal
= (exp
.uFlags
& FL_ORDINAL
);
1193 /* Check whether the current export is an OLE export, in case any of these tests pass */
1194 if (bIsNotPrivate
|| bHasOrdinal
)
1196 for (i
= 0; i
< ARRAYSIZE(astrOlePrivateExports
); ++i
)
1198 if (strlen(astrOlePrivateExports
[i
]) == exp
.strName
.len
&&
1199 strncmp(exp
.strName
.buf
, astrOlePrivateExports
[i
], exp
.strName
.len
) == 0)
1201 /* The current export is an OLE export: display the corresponding warning */
1204 fprintf(stderr
, "WARNING: %s line %d: Exported symbol '%.*s' should be PRIVATE\n",
1205 pszSourceFileName
, nLine
, exp
.strName
.len
, exp
.strName
.buf
);
1209 fprintf(stderr
, "WARNING: %s line %d: exported symbol '%.*s' should not be assigned an ordinal\n",
1210 pszSourceFileName
, nLine
, exp
.strName
.len
, exp
.strName
.buf
);
1218 OutputLine(fileDest
, &exp
);
1227 printf("syntax: spec2def [<options> ...] <spec file>\n"
1228 "Possible options:\n"
1229 " -h --help print this help screen\n"
1230 " -l=<file> generate an asm lib stub\n"
1231 " -d=<file> generate a def file\n"
1232 " -s=<file> generate a stub file\n"
1233 " --ms MSVC compatibility\n"
1234 " -n=<name> name of the dll\n"
1235 " --implib generate a def file for an import library\n"
1236 " --no-private-warnings suppress warnings about symbols that should be -private\n"
1237 " -a=<arch> set architecture to <arch> (i386, x86_64, arm)\n"
1238 " --with-tracing generate wine-like \"+relay\" trace trampolines (needs -s)\n");
1241 int main(int argc
, char *argv
[])
1244 char *pszSource
, *pszDefFileName
= NULL
, *pszStubFileName
= NULL
, *pszLibStubName
= NULL
;
1245 const char* pszVersionOption
= "--version=0x";
1246 char achDllName
[40];
1257 for (i
= 1; i
< argc
&& *argv
[i
] == '-'; i
++)
1259 if ((strcasecmp(argv
[i
], "--help") == 0) ||
1260 (strcasecmp(argv
[i
], "-h") == 0))
1265 else if (argv
[i
][1] == 'd' && argv
[i
][2] == '=')
1267 pszDefFileName
= argv
[i
] + 3;
1269 else if (argv
[i
][1] == 'l' && argv
[i
][2] == '=')
1271 pszLibStubName
= argv
[i
] + 3;
1273 else if (argv
[i
][1] == 's' && argv
[i
][2] == '=')
1275 pszStubFileName
= argv
[i
] + 3;
1277 else if (argv
[i
][1] == 'n' && argv
[i
][2] == '=')
1279 pszDllName
= argv
[i
] + 3;
1281 else if (strncasecmp(argv
[i
], pszVersionOption
, strlen(pszVersionOption
)) == 0)
1283 guOsVersion
= strtoul(argv
[i
] + strlen(pszVersionOption
), NULL
, 16);
1285 else if (strcasecmp(argv
[i
], "--implib") == 0)
1289 else if (strcasecmp(argv
[i
], "--ms") == 0)
1293 else if (strcasecmp(argv
[i
], "--no-private-warnings") == 0)
1295 gbNotPrivateNoWarn
= 1;
1297 else if (strcasecmp(argv
[i
], "--with-tracing") == 0)
1299 if (!pszStubFileName
)
1301 fprintf(stderr
, "Error: cannot use --with-tracing without -s option.\n");
1306 else if (argv
[i
][1] == 'a' && argv
[i
][2] == '=')
1308 pszArchString
= argv
[i
] + 3;
1312 fprintf(stderr
, "Unrecognized option: %s\n", argv
[i
]);
1317 if (strcasecmp(pszArchString
, "i386") == 0)
1320 gpszUnderscore
= "_";
1322 else if (strcasecmp(pszArchString
, "x86_64") == 0) giArch
= ARCH_AMD64
;
1323 else if (strcasecmp(pszArchString
, "ia64") == 0) giArch
= ARCH_IA64
;
1324 else if (strcasecmp(pszArchString
, "arm") == 0) giArch
= ARCH_ARM
;
1325 else if (strcasecmp(pszArchString
, "ppc") == 0) giArch
= ARCH_PPC
;
1327 if ((giArch
== ARCH_AMD64
) || (giArch
== ARCH_IA64
))
1329 pszArchString2
= "win64";
1332 pszArchString2
= "win32";
1334 /* Set a default dll name */
1340 p1
= strrchr(argv
[i
], '\\');
1341 if (!p1
) p1
= strrchr(argv
[i
], '/');
1342 p2
= p1
= p1
? p1
+ 1 : argv
[i
];
1344 /* walk up to '.' */
1345 while (*p2
!= '.' && *p2
!= 0) p2
++;
1347 if (len
>= sizeof(achDllName
) - 5)
1349 fprintf(stderr
, "name too long: %s\n", p1
);
1353 strncpy(achDllName
, p1
, len
);
1354 strncpy(achDllName
+ len
, ".dll", sizeof(achDllName
) - len
);
1355 pszDllName
= achDllName
;
1358 /* Open input file */
1359 pszSourceFileName
= argv
[i
];
1360 file
= fopen(pszSourceFileName
, "r");
1363 fprintf(stderr
, "error: could not open file %s\n", pszSourceFileName
);
1368 fseek(file
, 0, SEEK_END
);
1369 nFileSize
= ftell(file
);
1372 /* Allocate memory buffer */
1373 pszSource
= malloc(nFileSize
+ 1);
1380 /* Load input file into memory */
1381 nFileSize
= fread(pszSource
, 1, nFileSize
, file
);
1384 /* Zero terminate the source */
1385 pszSource
[nFileSize
] = '\0';
1389 /* Open output file */
1390 file
= fopen(pszDefFileName
, "w");
1393 fprintf(stderr
, "error: could not open output file %s\n", argv
[i
+ 1]);
1397 OutputHeader_def(file
, pszDllName
);
1398 result
= ParseFile(pszSource
, file
, OutputLine_def
);
1402 if (pszStubFileName
)
1404 /* Open output file */
1405 file
= fopen(pszStubFileName
, "w");
1408 fprintf(stderr
, "error: could not open output file %s\n", argv
[i
+ 1]);
1412 OutputHeader_stub(file
);
1413 result
= ParseFile(pszSource
, file
, OutputLine_stub
);
1419 /* Open output file */
1420 file
= fopen(pszLibStubName
, "w");
1423 fprintf(stderr
, "error: could not open output file %s\n", argv
[i
+ 1]);
1427 OutputHeader_asmstub(file
, pszDllName
);
1428 result
= ParseFile(pszSource
, file
, OutputLine_asmstub
);
1429 fprintf(file
, "\n END\n");