b6c29cc410baaf9742bf4f26f8c65989be4ee32c
7 #define strcasecmp _stricmp
10 typedef struct _STRING
20 int nCallingConvention
;
38 typedef int (*PFNOUTLINE
)(FILE *, EXPORT
*);
42 int giArch
= ARCH_X86
;
43 char *pszArchString
= "i386";
46 char *gpszUnderscore
= "";
48 #define DbgPrint(...) (!gbDebug || fprintf(stderr, __VA_ARGS__))
83 char* astrCallingConventions
[] =
96 return ((chr
<= ',' && chr
!= '$') ||
97 (chr
>= ':' && chr
< '?') );
101 CompareToken(const char *token
, const char *comparand
)
105 if (*token
!= *comparand
) return 0;
109 if (!IsSeparator(*token
)) return 0;
114 ScanToken(const char *token
, char chr
)
116 while (!IsSeparator(*token
))
118 if (*token
== chr
) return token
;
129 if (pc
[0] == '\n' && pc
[1] == '\r') return pc
+ 2;
130 else if (pc
[0] == '\n') return pc
+ 1;
137 TokenLength(char *pc
)
141 while (!IsSeparator(*pc
++)) length
++;
150 while (!IsSeparator(*pc
)) pc
++;
152 /* Skip white spaces */
153 while (*pc
== ' ' || *pc
== '\t') pc
++;
155 /* Check for end of line */
156 if (*pc
== '\n' || *pc
== '\r' || *pc
== 0) return 0;
158 /* Check for comment */
159 if (*pc
== '#' || *pc
== ';') return 0;
165 OutputHeader_stub(FILE *file
)
167 fprintf(file
, "/* This file is autogenerated, do not edit. */\n\n"
168 "#include <stubs.h>\n");
172 fprintf(file
, "#include <wine/debug.h>\n");
173 fprintf(file
, "#include <inttypes.h>\n");
174 fprintf(file
, "WINE_DECLARE_DEBUG_CHANNEL(relay);\n");
181 OutputLine_stub(FILE *file
, EXPORT
*pexp
)
185 int bInPrototype
= 0;
187 if (pexp
->nCallingConvention
!= CC_STUB
&&
188 (pexp
->uFlags
& FL_STUB
) == 0)
190 /* Only relay trace stdcall C functions */
191 if (!gbTracing
|| (pexp
->nCallingConvention
!= CC_STDCALL
)
192 || (pexp
->uFlags
& FL_NORELAY
)
193 || (pexp
->strName
.buf
[0] == '?'))
200 /* Declare the "real" function */
203 fprintf(file
, "extern ");
209 if (pexp
->uFlags
& FL_REGISTER
)
211 /* FIXME: Not sure this is right */
212 fprintf(file
, "void ");
214 else if (pexp
->uFlags
& FL_RET64
)
216 fprintf(file
, "__int64 ");
220 fprintf(file
, "int ");
223 if ((giArch
== ARCH_X86
) &&
224 pexp
->nCallingConvention
== CC_STDCALL
)
226 fprintf(file
, "__stdcall ");
230 if (pexp
->strName
.buf
[0] == '?')
232 fprintf(file
, "stub_function%d(", pexp
->nNumber
);
236 if (!bRelay
|| bInPrototype
)
237 fprintf(file
, "%.*s(", pexp
->strName
.len
, pexp
->strName
.buf
);
239 fprintf(file
, "$relaytrace$%.*s(", pexp
->strName
.len
, pexp
->strName
.buf
);
242 for (i
= 0; i
< pexp
->nArgCount
; i
++)
244 if (i
!= 0) fprintf(file
, ", ");
245 switch (pexp
->anArgs
[i
])
247 case ARG_LONG
: fprintf(file
, "long"); break;
248 case ARG_PTR
: fprintf(file
, "void*"); break;
249 case ARG_STR
: fprintf(file
, "char*"); break;
250 case ARG_WSTR
: fprintf(file
, "wchar_t*"); break;
251 case ARG_DBL
: fprintf(file
, "double"); break;
252 case ARG_INT64
: fprintf(file
, "__int64"); break;
253 case ARG_INT128
: fprintf(file
, "__int128"); break;
254 case ARG_FLOAT
: fprintf(file
, "float"); break;
256 fprintf(file
, " a%d", i
);
261 fprintf(file
, ");\n\n");
263 } while (bInPrototype
--);
267 fprintf(file
, ")\n{\n\tDbgPrint(\"WARNING: calling stub %.*s(",
268 pexp
->strName
.len
, pexp
->strName
.buf
);
272 fprintf(file
, ")\n{\n");
273 if (pexp
->uFlags
& FL_REGISTER
)
275 /* No return value */
277 else if (pexp
->uFlags
& FL_RET64
)
279 fprintf(file
, "\t__int64 retval;\n");
283 fprintf(file
, "\tint retval;\n");
285 fprintf(file
, "\tif (TRACE_ON(relay))\n\t\tDPRINTF(\"%s: %.*s(",
286 pszDllName
, pexp
->strName
.len
, pexp
->strName
.buf
);
289 for (i
= 0; i
< pexp
->nArgCount
; i
++)
291 if (i
!= 0) fprintf(file
, ",");
292 switch (pexp
->anArgs
[i
])
294 case ARG_LONG
: fprintf(file
, "0x%%lx"); break;
295 case ARG_PTR
: fprintf(file
, "0x%%p"); break;
296 case ARG_STR
: fprintf(file
, "'%%s'"); break;
297 case ARG_WSTR
: fprintf(file
, "'%%ws'"); break;
298 case ARG_DBL
: fprintf(file
, "%%f"); break;
299 case ARG_INT64
: fprintf(file
, "%%\"PRix64\""); break;
300 case ARG_INT128
: fprintf(file
, "%%\"PRix128\""); break;
301 case ARG_FLOAT
: fprintf(file
, "%%f"); break;
304 fprintf(file
, ")\\n\"");
306 for (i
= 0; i
< pexp
->nArgCount
; i
++)
309 switch (pexp
->anArgs
[i
])
311 case ARG_LONG
: fprintf(file
, "(long)a%d", i
); break;
312 case ARG_PTR
: fprintf(file
, "(void*)a%d", i
); break;
313 case ARG_STR
: fprintf(file
, "(char*)a%d", i
); break;
314 case ARG_WSTR
: fprintf(file
, "(wchar_t*)a%d", i
); break;
315 case ARG_DBL
: fprintf(file
, "(double)a%d", i
); break;
316 case ARG_INT64
: fprintf(file
, "(__int64)a%d", i
); break;
317 case ARG_INT128
: fprintf(file
, "(__int128)a%d", i
); break;
318 case ARG_FLOAT
: fprintf(file
, "(float)a%d", i
); break;
321 fprintf(file
, ");\n");
323 if (pexp
->nCallingConvention
== CC_STUB
)
325 fprintf(file
, "\t__wine_spec_unimplemented_stub(\"%s\", __FUNCTION__);\n", pszDllName
);
329 if (pexp
->uFlags
& FL_REGISTER
)
335 fprintf(file
, "\tretval = ");
337 fprintf(file
, "%.*s(", pexp
->strName
.len
, pexp
->strName
.buf
);
339 for (i
= 0; i
< pexp
->nArgCount
; i
++)
341 if (i
!= 0) fprintf(file
, ", ");
342 fprintf(file
, "a%d", i
);
344 fprintf(file
, ");\n");
348 fprintf(file
, "\treturn 0;\n}\n\n");
349 else if ((pexp
->uFlags
& FL_REGISTER
) == 0)
351 if (pexp
->uFlags
& FL_RET64
)
353 fprintf(file
, "\tif (TRACE_ON(relay))\n\t\tDPRINTF(\"%s: %.*s: retval = %%\"PRIx64\"\\n\", retval);\n",
354 pszDllName
, pexp
->strName
.len
, pexp
->strName
.buf
);
358 fprintf(file
, "\tif (TRACE_ON(relay))\n\t\tDPRINTF(\"%s: %.*s: retval = 0x%%lx\\n\", retval);\n",
359 pszDllName
, pexp
->strName
.len
, pexp
->strName
.buf
);
361 fprintf(file
, "\treturn retval;\n}\n\n");
368 OutputHeader_asmstub(FILE *file
, char *libname
)
370 fprintf(file
, "; File generated automatically, do not edit! \n\n");
372 if (giArch
== ARCH_X86
)
374 fprintf(file
, ".586\n.model flat\n.code\n");
376 else if (giArch
== ARCH_AMD64
)
378 fprintf(file
, ".code\n");
380 else if (giArch
== ARCH_ARM
)
383 " AREA |.text|,ALIGN=2,CODE,READONLY\n\n");
388 Output_symbol(FILE *fileDest
, char* pszSymbolName
)
390 if (giArch
== ARCH_ARM
)
393 " EXPORT %s [FUNC]\n%s\n",
400 "PUBLIC %s\n%s: nop\n",
407 OutputLine_asmstub(FILE *fileDest
, EXPORT
*pexp
)
409 char szNameBuffer
[128];
411 /* Handle autoname */
412 if (pexp
->strName
.len
== 1 && pexp
->strName
.buf
[0] == '@')
414 sprintf(szNameBuffer
, "%sordinal%d\n%sordinal%d: nop\n",
415 gpszUnderscore
, pexp
->nOrdinal
, gpszUnderscore
, pexp
->nOrdinal
);
417 else if (giArch
!= ARCH_X86
)
419 sprintf(szNameBuffer
, "_stub_%.*s",
420 pexp
->strName
.len
, pexp
->strName
.buf
);
422 else if (pexp
->nCallingConvention
== CC_STDCALL
)
424 sprintf(szNameBuffer
, "__stub_%.*s@%d",
425 pexp
->strName
.len
, pexp
->strName
.buf
, pexp
->nStackBytes
);
427 else if (pexp
->nCallingConvention
== CC_FASTCALL
)
429 sprintf(szNameBuffer
, "@_stub_%.*s@%d",
430 pexp
->strName
.len
, pexp
->strName
.buf
, pexp
->nStackBytes
);
432 else if (pexp
->nCallingConvention
== CC_CDECL
||
433 pexp
->nCallingConvention
== CC_STUB
)
435 sprintf(szNameBuffer
, "__stub_%.*s",
436 pexp
->strName
.len
, pexp
->strName
.buf
);
438 else if (pexp
->nCallingConvention
== CC_EXTERN
)
440 sprintf(szNameBuffer
, "__stub_%.*s",
441 pexp
->strName
.len
, pexp
->strName
.buf
);
444 Output_symbol(fileDest
, szNameBuffer
);
450 OutputHeader_def(FILE *file
, char *libname
)
453 "; File generated automatically, do not edit!\n\n"
460 PrintName(FILE *fileDest
, EXPORT
*pexp
, PSTRING pstr
, int fDeco
)
462 const char *pcName
= pstr
->buf
;
463 int nNameLength
= pstr
->len
;
464 const char* pcDot
, *pcAt
;
466 /* Check for non-x86 first */
467 if (giArch
!= ARCH_X86
)
469 /* Does the string already have stdcall decoration? */
470 pcAt
= ScanToken(pcName
, '@');
471 if (pcAt
&& (pcAt
< (pcName
+ nNameLength
)) && (pcName
[0] == '_'))
473 /* Skip leading underscore and remove trailing decoration */
475 nNameLength
= pcAt
- pcName
;
478 /* Print the undecorated function name */
479 fprintf(fileDest
, "%.*s", nNameLength
, pcName
);
482 ((pexp
->nCallingConvention
== CC_STDCALL
) ||
483 (pexp
->nCallingConvention
== CC_FASTCALL
)))
485 /* Scan for a dll forwarding dot */
486 pcDot
= ScanToken(pcName
, '.');
489 /* First print the dll name, followed by a dot */
490 nNameLength
= pcDot
- pcName
;
491 fprintf(fileDest
, "%.*s.", nNameLength
, pcName
);
493 /* Now the actual function name */
495 nNameLength
= pexp
->strTarget
.len
- nNameLength
- 1;
498 /* Does the string already have decoration? */
499 pcAt
= ScanToken(pcName
, '@');
500 if (pcAt
&& (pcAt
< (pcName
+ nNameLength
)))
502 /* On GCC, we need to remove the leading stdcall underscore */
503 if (!gbMSComp
&& (pexp
->nCallingConvention
== CC_STDCALL
))
509 /* Print the already decorated function name */
510 fprintf(fileDest
, "%.*s", nNameLength
, pcName
);
514 /* Print the prefix, but skip it for (GCC && stdcall) */
515 if (gbMSComp
|| (pexp
->nCallingConvention
!= CC_STDCALL
))
517 fprintf(fileDest
, "%c", pexp
->nCallingConvention
== CC_FASTCALL
? '@' : '_');
520 /* Print the name with trailing decoration */
521 fprintf(fileDest
, "%.*s@%d", nNameLength
, pcName
, pexp
->nStackBytes
);
526 /* Print the undecorated function name */
527 fprintf(fileDest
, "%.*s", nNameLength
, pcName
);
532 OutputLine_def_MS(FILE *fileDest
, EXPORT
*pexp
)
534 PrintName(fileDest
, pexp
, &pexp
->strName
, 0);
538 /* Redirect to a stub function, to get the right decoration in the lib */
539 fprintf(fileDest
, "=_stub_%.*s", pexp
->strName
.len
, pexp
->strName
.buf
);
541 else if (pexp
->strTarget
.buf
)
543 if (pexp
->strName
.buf
[0] == '?')
545 fprintf(stderr
, "warning: ignoring C++ redirection %.*s -> %.*s\n",
546 pexp
->strName
.len
, pexp
->strName
.buf
, pexp
->strTarget
.len
, pexp
->strTarget
.buf
);
550 fprintf(fileDest
, "=");
552 /* If the original name was decorated, use decoration in the forwarder as well */
553 if ((giArch
== ARCH_X86
) && ScanToken(pexp
->strName
.buf
, '@') &&
554 !ScanToken(pexp
->strTarget
.buf
, '@') &&
555 ((pexp
->nCallingConvention
== CC_STDCALL
) ||
556 (pexp
->nCallingConvention
== CC_FASTCALL
)) )
558 PrintName(fileDest
, pexp
, &pexp
->strTarget
, 1);
562 /* Write the undecorated redirection name */
563 fprintf(fileDest
, "%.*s", pexp
->strTarget
.len
, pexp
->strTarget
.buf
);
567 else if (((pexp
->uFlags
& FL_STUB
) || (pexp
->nCallingConvention
== CC_STUB
)) &&
568 (pexp
->strName
.buf
[0] == '?'))
570 /* C++ stubs are forwarded to C stubs */
571 fprintf(fileDest
, "=stub_function%d", pexp
->nNumber
);
573 else if (gbTracing
&& ((pexp
->uFlags
& FL_NORELAY
) == 0) && (pexp
->nCallingConvention
== CC_STDCALL
) &&
574 (pexp
->strName
.buf
[0] != '?'))
576 /* Redirect it to the relay-tracing trampoline */
577 fprintf(fileDest
, "=$relaytrace$%.*s", pexp
->strName
.len
, pexp
->strName
.buf
);
582 OutputLine_def_GCC(FILE *fileDest
, EXPORT
*pexp
)
585 /* Print the function name, with decoration for export libs */
586 PrintName(fileDest
, pexp
, &pexp
->strName
, gbImportLib
);
587 DbgPrint("Generating def line for '%.*s'\n", pexp
->strName
.len
, pexp
->strName
.buf
);
589 /* Check if this is a forwarded export */
590 if (pexp
->strTarget
.buf
)
592 int fIsExternal
= !!ScanToken(pexp
->strTarget
.buf
, '.');
593 DbgPrint("Got redirect '%.*s'\n", pexp
->strTarget
.len
, pexp
->strTarget
.buf
);
595 /* print the target name, don't decorate if it is external */
596 fprintf(fileDest
, "=");
597 PrintName(fileDest
, pexp
, &pexp
->strTarget
, !fIsExternal
);
599 else if (((pexp
->uFlags
& FL_STUB
) || (pexp
->nCallingConvention
== CC_STUB
)) &&
600 (pexp
->strName
.buf
[0] == '?'))
602 /* C++ stubs are forwarded to C stubs */
603 fprintf(fileDest
, "=stub_function%d", pexp
->nNumber
);
605 else if (gbTracing
&& ((pexp
->uFlags
& FL_NORELAY
) == 0) && (pexp
->nCallingConvention
== CC_STDCALL
) &&
606 (pexp
->strName
.buf
[0] != '?'))
608 /* Redirect it to the relay-tracing trampoline */
611 fprintf(fileDest
, "=");
612 sprintf(buf
, "$relaytrace$%.*s", pexp
->strName
.len
, pexp
->strName
.buf
);
614 strTarget
.len
= pexp
->strName
.len
+ 12;
615 PrintName(fileDest
, pexp
, &strTarget
, 1);
619 /* Special handling for stdcall and fastcall */
620 if ((giArch
== ARCH_X86
) &&
621 ((pexp
->nCallingConvention
== CC_STDCALL
) ||
622 (pexp
->nCallingConvention
== CC_FASTCALL
)))
624 /* Is this the import lib? */
627 /* Is the name in the spec file decorated? */
628 const char* pcDeco
= ScanToken(pexp
->strName
.buf
, '@');
629 if (pcDeco
&& (pcDeco
< pexp
->strName
.buf
+ pexp
->strName
.len
))
631 /* Write the name including the leading @ */
632 fprintf(fileDest
, "==%.*s", pexp
->strName
.len
, pexp
->strName
.buf
);
635 else if ((!pexp
->strTarget
.buf
) && !(bTracing
))
637 /* Write a forwarder to the actual decorated symbol */
638 fprintf(fileDest
, "=");
639 PrintName(fileDest
, pexp
, &pexp
->strName
, 1);
645 OutputLine_def(FILE *fileDest
, EXPORT
*pexp
)
647 DbgPrint("OutputLine_def: '%.*s'...\n", pexp
->strName
.len
, pexp
->strName
.buf
);
648 fprintf(fileDest
, " ");
651 OutputLine_def_MS(fileDest
, pexp
);
653 OutputLine_def_GCC(fileDest
, pexp
);
655 if (pexp
->uFlags
& FL_ORDINAL
)
657 fprintf(fileDest
, " @%d", pexp
->nOrdinal
);
660 if (pexp
->uFlags
& FL_NONAME
)
662 fprintf(fileDest
, " NONAME");
665 if (pexp
->uFlags
& FL_PRIVATE
)
667 fprintf(fileDest
, " PRIVATE");
670 if (pexp
->nCallingConvention
== CC_EXTERN
)
672 fprintf(fileDest
, " DATA");
675 fprintf(fileDest
, "\n");
681 ParseFile(char* pcStart
, FILE *fileDest
, PFNOUTLINE OutputLine
)
689 //fprintf(stderr, "info: line %d, pcStart:'%.30s'\n", nLine, pcStart);
694 for (pcLine
= pcStart
; *pcLine
; pcLine
= NextLine(pcLine
), nLine
++)
703 //if (!strncmp(pcLine, "22 stdcall @(long) MPR_Alloc",28))
706 //fprintf(stderr, "info: line %d, token:'%d, %.20s'\n",
707 // nLine, TokenLength(pcLine), pcLine);
709 /* Skip white spaces */
710 while (*pc
== ' ' || *pc
== '\t') pc
++;
712 /* Skip empty lines, stop at EOF */
713 if (*pc
== ';' || *pc
<= '#') continue;
714 if (*pc
== 0) return 0;
716 //fprintf(stderr, "info: line %d, token:'%.*s'\n",
717 // nLine, TokenLength(pc), pc);
719 /* Now we should get either an ordinal or @ */
724 exp
.nOrdinal
= atol(pc
);
725 /* The import lib should contain the ordinal only if -ordinal was specified */
727 exp
.uFlags
|= FL_ORDINAL
;
730 /* Go to next token (type) */
731 if (!(pc
= NextToken(pc
)))
733 fprintf(stderr
, "error: line %d, unexpected end of line\n", nLine
);
737 //fprintf(stderr, "info: Token:'%.*s'\n", TokenLength(pc), pc);
739 /* Now we should get the type */
740 if (CompareToken(pc
, "stdcall"))
742 exp
.nCallingConvention
= CC_STDCALL
;
744 else if (CompareToken(pc
, "cdecl") ||
745 CompareToken(pc
, "varargs"))
747 exp
.nCallingConvention
= CC_CDECL
;
749 else if (CompareToken(pc
, "fastcall"))
751 exp
.nCallingConvention
= CC_FASTCALL
;
753 else if (CompareToken(pc
, "thiscall"))
755 exp
.nCallingConvention
= CC_THISCALL
;
757 else if (CompareToken(pc
, "extern"))
759 exp
.nCallingConvention
= CC_EXTERN
;
761 else if (CompareToken(pc
, "stub"))
763 exp
.nCallingConvention
= CC_STUB
;
767 fprintf(stderr
, "error: line %d, expected callconv, got '%.*s' %d\n",
768 nLine
, TokenLength(pc
), pc
, *pc
);
772 //fprintf(stderr, "info: nCallingConvention: %d\n", exp.nCallingConvention);
774 /* Go to next token (options or name) */
775 if (!(pc
= NextToken(pc
)))
777 fprintf(stderr
, "fail2\n");
785 if (CompareToken(pc
, "-arch"))
787 /* Default to not included */
791 /* Look if we are included */
792 while (*pc
== '=' || *pc
== ',')
795 if (CompareToken(pc
, pszArchString
) ||
796 CompareToken(pc
, pszArchString2
))
801 /* Skip to next arch or end */
802 while (*pc
> ',') pc
++;
805 else if (CompareToken(pc
, "-i386"))
807 if (giArch
!= ARCH_X86
) included
= 0;
809 else if (CompareToken(pc
, "-private"))
811 exp
.uFlags
|= FL_PRIVATE
;
813 else if (CompareToken(pc
, "-noname"))
815 exp
.uFlags
|= FL_ORDINAL
| FL_NONAME
;
817 else if (CompareToken(pc
, "-ordinal"))
819 exp
.uFlags
|= FL_ORDINAL
;
820 /* GCC doesn't automatically import by ordinal if an ordinal
821 * is found in the def file. Force it. */
822 if (gbImportLib
&& !gbMSComp
)
823 exp
.uFlags
|= FL_NONAME
;
825 else if (CompareToken(pc
, "-stub"))
827 exp
.uFlags
|= FL_STUB
;
829 else if (CompareToken(pc
, "-norelay"))
831 exp
.uFlags
|= FL_NORELAY
;
833 else if (CompareToken(pc
, "-ret64"))
835 exp
.uFlags
|= FL_RET64
;
837 else if (CompareToken(pc
, "-register"))
839 exp
.uFlags
|= FL_REGISTER
;
843 fprintf(stderr
, "info: ignored option: '%.*s'\n",
844 TokenLength(pc
), pc
);
847 /* Go to next token */
851 //fprintf(stderr, "info: Name:'%.10s'\n", pc);
853 /* If arch didn't match ours, skip this entry */
854 if (!included
) continue;
857 exp
.strName
.buf
= pc
;
858 exp
.strName
.len
= TokenLength(pc
);
859 DbgPrint("Got name: '%.*s'\n", exp
.strName
.len
, exp
.strName
.buf
);
861 /* Check for autoname */
862 if ((exp
.strName
.len
== 1) && (exp
.strName
.buf
[0] == '@'))
864 sprintf(namebuffer
, "ordinal%d", exp
.nOrdinal
);
865 exp
.strName
.len
= strlen(namebuffer
);
866 exp
.strName
.buf
= namebuffer
;
867 exp
.uFlags
|= FL_ORDINAL
| FL_NONAME
;
870 /* Handle parameters */
872 if (exp
.nCallingConvention
!= CC_EXTERN
&&
873 exp
.nCallingConvention
!= CC_STUB
)
875 /* Go to next token */
876 if (!(pc
= NextToken(pc
)))
878 fprintf(stderr
, "fail4\n");
885 fprintf(stderr
, "error: line %d, expected '('\n", nLine
);
889 /* Skip whitespaces */
890 while (*pc
== ' ' || *pc
== '\t') pc
++;
895 if (CompareToken(pc
, "long"))
897 exp
.nStackBytes
+= 4;
898 exp
.anArgs
[exp
.nArgCount
] = ARG_LONG
;
900 else if (CompareToken(pc
, "double"))
902 exp
.nStackBytes
+= 8;
903 exp
.anArgs
[exp
.nArgCount
] = ARG_DBL
;
905 else if (CompareToken(pc
, "ptr"))
907 exp
.nStackBytes
+= 4; // sizeof(void*) on x86
908 exp
.anArgs
[exp
.nArgCount
] = ARG_PTR
;
910 else if (CompareToken(pc
, "str"))
912 exp
.nStackBytes
+= 4; // sizeof(void*) on x86
913 exp
.anArgs
[exp
.nArgCount
] = ARG_STR
;
915 else if (CompareToken(pc
, "wstr"))
917 exp
.nStackBytes
+= 4; // sizeof(void*) on x86
918 exp
.anArgs
[exp
.nArgCount
] = ARG_WSTR
;
920 else if (CompareToken(pc
, "int64"))
922 exp
.nStackBytes
+= 8;
923 exp
.anArgs
[exp
.nArgCount
] = ARG_INT64
;
925 else if (CompareToken(pc
, "int128"))
927 exp
.nStackBytes
+= 16;
928 exp
.anArgs
[exp
.nArgCount
] = ARG_INT128
;
930 else if (CompareToken(pc
, "float"))
932 exp
.nStackBytes
+= 4;
933 exp
.anArgs
[exp
.nArgCount
] = ARG_FLOAT
;
936 fprintf(stderr
, "error: line %d, expected type, got: %.10s\n", nLine
, pc
);
940 /* Go to next parameter */
941 if (!(pc
= NextToken(pc
)))
943 fprintf(stderr
, "fail5\n");
951 fprintf(stderr
, "error: line %d, expected ')'\n", nLine
);
956 /* Handle special stub cases */
957 if (exp
.nCallingConvention
== CC_STUB
)
959 /* Check for c++ mangled name */
962 //printf("Found c++ mangled name...\n");
967 /* Check for stdcall name */
968 const char *p
= ScanToken(pc
, '@');
969 if (p
&& (p
- pc
< exp
.strName
.len
))
973 /* Truncate the name to before the @ */
974 exp
.strName
.len
= (int)(p
- pc
);
975 if (exp
.strName
.len
< 1)
977 fprintf(stderr
, "error, @ in line %d\n", nLine
);
980 exp
.nStackBytes
= atoi(p
+ 1);
981 exp
.nArgCount
= exp
.nStackBytes
/ 4;
982 exp
.nCallingConvention
= CC_STDCALL
;
983 exp
.uFlags
|= FL_STUB
;
984 for (i
= 0; i
< exp
.nArgCount
; i
++)
985 exp
.anArgs
[i
] = ARG_LONG
;
990 /* Get optional redirection */
994 exp
.strTarget
.buf
= pc
;
995 exp
.strTarget
.len
= TokenLength(pc
);
997 /* Check syntax (end of line) */
1000 fprintf(stderr
, "error: line %d, additional tokens after ')'\n", nLine
);
1004 /* Don't relay-trace forwarded functions */
1005 exp
.uFlags
|= FL_NORELAY
;
1009 exp
.strTarget
.buf
= 0;
1010 exp
.strTarget
.len
= 0;
1013 /* Check for no-name without ordinal */
1014 if ((exp
.uFlags
& FL_ORDINAL
) && (exp
.nOrdinal
== -1))
1016 fprintf(stderr
, "error: line %d, ordinal export without ordinal!\n", nLine
);
1020 OutputLine(fileDest
, &exp
);
1030 printf("syntax: spec2def [<options> ...] <spec file>\n"
1031 "Possible options:\n"
1032 " -h --help prints this screen\n"
1033 " -l=<file> generates an asm lib stub\n"
1034 " -d=<file> generates a def file\n"
1035 " -s=<file> generates a stub file\n"
1036 " --ms msvc compatibility\n"
1037 " -n=<name> name of the dll\n"
1038 " --implib generate a def file for an import library\n"
1039 " -a=<arch> Set architecture to <arch>. (i386, x86_64, arm)\n"
1040 " --with-tracing generates wine-like \"+relay\" trace trampolines. (necessitates -s)\n");
1043 int main(int argc
, char *argv
[])
1046 char *pszSource
, *pszDefFileName
= 0, *pszStubFileName
= 0, *pszLibStubName
= 0;
1047 char achDllName
[40];
1058 for (i
= 1; i
< argc
&& *argv
[i
] == '-'; i
++)
1060 if ((strcasecmp(argv
[i
], "--help") == 0) ||
1061 (strcasecmp(argv
[i
], "-h") == 0))
1066 else if (argv
[i
][1] == 'd' && argv
[i
][2] == '=')
1068 pszDefFileName
= argv
[i
] + 3;
1070 else if (argv
[i
][1] == 'l' && argv
[i
][2] == '=')
1072 pszLibStubName
= argv
[i
] + 3;
1074 else if (argv
[i
][1] == 's' && argv
[i
][2] == '=')
1076 pszStubFileName
= argv
[i
] + 3;
1078 else if (argv
[i
][1] == 'n' && argv
[i
][2] == '=')
1080 pszDllName
= argv
[i
] + 3;
1082 else if ((strcasecmp(argv
[i
], "--implib") == 0))
1086 else if ((strcasecmp(argv
[i
], "--ms") == 0))
1090 else if ((strcasecmp(argv
[i
], "--with-tracing") == 0))
1092 if (!pszStubFileName
)
1094 fprintf(stderr
, "Error: cannot use --with-tracing without -s option.\n");
1099 else if (argv
[i
][1] == 'a' && argv
[i
][2] == '=')
1101 pszArchString
= argv
[i
] + 3;
1105 fprintf(stderr
, "Unrecognized option: %s\n", argv
[i
]);
1110 if (strcasecmp(pszArchString
, "i386") == 0)
1113 gpszUnderscore
= "_";
1115 else if (strcasecmp(pszArchString
, "x86_64") == 0) giArch
= ARCH_AMD64
;
1116 else if (strcasecmp(pszArchString
, "ia64") == 0) giArch
= ARCH_IA64
;
1117 else if (strcasecmp(pszArchString
, "arm") == 0) giArch
= ARCH_ARM
;
1118 else if (strcasecmp(pszArchString
, "ppc") == 0) giArch
= ARCH_PPC
;
1120 if ((giArch
== ARCH_AMD64
) || (giArch
== ARCH_IA64
))
1122 pszArchString2
= "win64";
1125 pszArchString2
= "win32";
1127 /* Set a default dll name */
1133 p1
= strrchr(argv
[i
], '\\');
1134 if (!p1
) p1
= strrchr(argv
[i
], '/');
1135 p2
= p1
= p1
? p1
+ 1 : argv
[i
];
1137 /* walk up to '.' */
1138 while (*p2
!= '.' && *p2
!= 0) p2
++;
1140 if (len
>= sizeof(achDllName
) - 5)
1142 fprintf(stderr
, "name too long: %s\n", p1
);
1146 strncpy(achDllName
, p1
, len
);
1147 strncpy(achDllName
+ len
, ".dll", sizeof(achDllName
) - len
);
1148 pszDllName
= achDllName
;
1151 /* Open input file argv[1] */
1152 file
= fopen(argv
[i
], "r");
1155 fprintf(stderr
, "error: could not open file %s ", argv
[i
]);
1160 fseek(file
, 0, SEEK_END
);
1161 nFileSize
= ftell(file
);
1164 /* Allocate memory buffer */
1165 pszSource
= malloc(nFileSize
+ 1);
1172 /* Load input file into memory */
1173 nFileSize
= fread(pszSource
, 1, nFileSize
, file
);
1176 /* Zero terminate the source */
1177 pszSource
[nFileSize
] = '\0';
1181 /* Open output file */
1182 file
= fopen(pszDefFileName
, "w");
1185 fprintf(stderr
, "error: could not open output file %s ", argv
[i
+ 1]);
1189 OutputHeader_def(file
, pszDllName
);
1190 result
= ParseFile(pszSource
, file
, OutputLine_def
);
1194 if (pszStubFileName
)
1196 /* Open output file */
1197 file
= fopen(pszStubFileName
, "w");
1200 fprintf(stderr
, "error: could not open output file %s ", argv
[i
+ 1]);
1204 OutputHeader_stub(file
);
1205 result
= ParseFile(pszSource
, file
, OutputLine_stub
);
1211 /* Open output file */
1212 file
= fopen(pszLibStubName
, "w");
1215 fprintf(stderr
, "error: could not open output file %s ", argv
[i
+ 1]);
1219 OutputHeader_asmstub(file
, pszDllName
);
1220 result
= ParseFile(pszSource
, file
, OutputLine_asmstub
);
1221 fprintf(file
, "\n END\n");