ReactOS 0.4.15-dev-8434-g155a7c7
spec2def.c
Go to the documentation of this file.
1#include <stdio.h>
2#include <stdlib.h>
3#include <ctype.h>
4#include <string.h>
5#include <stdarg.h>
6
7#ifdef _MSC_VER
8#define strcasecmp(_String1, _String2) _stricmp(_String1, _String2)
9#define strncasecmp(_String1, _String2, _MaxCount) _strnicmp(_String1, _String2, _MaxCount)
10#endif
11
12#define ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0]))
13
14typedef struct _STRING
15{
16 const char *buf;
17 int len;
19
20typedef struct
21{
28 int anArgs[30];
29 unsigned int uFlags;
31 unsigned nStartVersion;
32 unsigned nEndVersion;
34} EXPORT;
35
36#if 0 // Debug helper function
37void
38PrintExport(EXPORT *pexp)
39{
40 fprintf(stderr, "strName='%.*s'\n", pexp->strName.len, pexp->strName.buf);
41 fprintf(stderr, "strName='%.*s'\n", pexp->strTarget.len, pexp->strTarget.buf);
42 fprintf(stderr, "nCallingConvention=%u\n", pexp->nCallingConvention);
43 fprintf(stderr, "nOrdinal=%u\n", pexp->nOrdinal);
44 fprintf(stderr, "nStackBytes=%u\n", pexp->nStackBytes);
45 fprintf(stderr, "nArgCount=%u\n", pexp->nArgCount);
46 fprintf(stderr, "uFlags=0x%x\n", pexp->uFlags);
47 fprintf(stderr, "nNumber=%u\n", pexp->nNumber);
48 fprintf(stderr, "nStartVersion=%u\n", pexp->nStartVersion);
49 fprintf(stderr, "nEndVersion=%u\n", pexp->nEndVersion);
50 fprintf(stderr, "bVersionIncluded=%u\n", pexp->bVersionIncluded);
51}
52#endif
53
55{
62};
63
64typedef int (*PFNOUTLINE)(FILE *, EXPORT *);
65int gbMSComp = 0;
68int gbTracing = 0;
70char *pszArchString = "i386";
74char *gpszUnderscore = "";
76unsigned guOsVersion = 0x502;
77#define DbgPrint(...) (!gbDebug || fprintf(stderr, __VA_ARGS__))
78
79enum
80{
88 FL_IMPSYM = 128,
89};
90
91enum
92{
99};
100
101enum
102{
112
114{
115 "STDCALL",
116 "CDECL",
117 "FASTCALL",
118 "THISCALL",
119 "EXTERN"
120};
121
122/*
123 * List of OLE exports that should be PRIVATE and not be assigned an ordinal.
124 * In case these conditions are not met when linking with MS LINK.EXE, warnings
125 * LNK4104 and LNK4222 respectively are emitted.
126 */
127static const char* astrOlePrivateExports[] =
128{
129 "DllCanUnloadNow",
130 "DllGetClassObject",
131 "DllGetClassFactoryFromClassString",
132 "DllGetDocumentation",
133 "DllInitialize",
134 "DllInstall",
135 "DllRegisterServer",
136 "DllRegisterServerEx",
137 "DllRegisterServerExW",
138 "DllUnload",
139 "DllUnregisterServer",
140 "RasCustomDeleteEntryNotify",
141 "RasCustomDial",
142 "RasCustomDialDlg",
143 "RasCustomEntryDlg",
144};
145
146static
147int
148IsSeparator(char chr)
149{
150 return ((chr <= ',' && chr != '$' && chr != '#') ||
151 (chr >= ':' && chr < '?') );
152}
153
154int
155CompareToken(const char *token, const char *comparand)
156{
157 while (*comparand)
158 {
159 if (*token != *comparand) return 0;
160 token++;
161 comparand++;
162 }
163 if (IsSeparator(comparand[-1])) return 1;
164 if (!IsSeparator(*token)) return 0;
165 return 1;
166}
167
168const char *
169ScanToken(const char *token, char chr)
170{
171 while (!IsSeparator(*token))
172 {
173 if (*token == chr) return token;
174 token++;
175 }
176 return 0;
177}
178
179const char *
180NextLine(const char *pc)
181{
182 while (*pc != 0)
183 {
184 if (pc[0] == '\n' && pc[1] == '\r') return pc + 2;
185 else if (pc[0] == '\n') return pc + 1;
186 pc++;
187 }
188 return pc;
189}
190
191int
192TokenLength(const char *pc)
193{
194 int length = 0;
195
196 while (!IsSeparator(*pc++)) length++;
197
198 return length;
199}
200
201const char *
202NextToken(const char *pc)
203{
204 /* Skip token */
205 while (!IsSeparator(*pc)) pc++;
206
207 /* Skip white spaces */
208 while (*pc == ' ' || *pc == '\t') pc++;
209
210 /* Check for end of line */
211 if (*pc == '\n' || *pc == '\r' || *pc == 0) return 0;
212
213 /* Check for comment */
214 if (*pc == '#' || *pc == ';') return 0;
215
216 return pc;
217}
218
219void
221{
222 fprintf(file, "/* This file is autogenerated, do not edit. */\n\n"
223 "#include <stubs.h>\n");
224
225 if (gbTracing)
226 {
227 fprintf(file, "#include <wine/debug.h>\n");
228 fprintf(file, "#include <inttypes.h>\n");
229 fprintf(file, "WINE_DECLARE_DEBUG_CHANNEL(relay);\n");
230 }
231
232 fprintf(file, "\n");
233}
234
235int
237{
238 int i;
239 int bRelay = 0;
240 int bInPrototype = 0;
241
242 /* Workaround for forwarded externs. See here for an explanation:
243 * https://stackoverflow.com/questions/4060143/forwarding-data-in-a-dll */
244 if (gbMSComp &&
245 (pexp->nCallingConvention == CC_EXTERN) &&
246 (pexp->strTarget.buf != NULL) &&
247 (!!ScanToken(pexp->strTarget.buf, '.')))
248 {
249 fprintf(file, "#pragma comment(linker,\"/export:%s%.*s=%.*s,DATA\")\n\n",
250 gpszUnderscore, pexp->strName.len, pexp->strName.buf, pexp->strTarget.len, pexp->strTarget.buf);
251 return 0;
252 }
253
254 if (pexp->nCallingConvention != CC_STUB &&
255 (pexp->uFlags & FL_STUB) == 0)
256 {
257 /* Only relay trace stdcall C functions */
258 if (!gbTracing || (pexp->nCallingConvention != CC_STDCALL)
259 || (pexp->uFlags & FL_NORELAY)
260 || (pexp->strName.buf[0] == '?'))
261 {
262 return 0;
263 }
264 bRelay = 1;
265 }
266
267 /* Declare the "real" function */
268 if (bRelay)
269 {
270 fprintf(file, "extern ");
271 bInPrototype = 1;
272 }
273
274 do
275 {
276 if (pexp->uFlags & FL_REGISTER)
277 {
278 /* FIXME: Not sure this is right */
279 fprintf(file, "void ");
280 }
281 else if (pexp->uFlags & FL_RET64)
282 {
283 fprintf(file, "__int64 ");
284 }
285 else
286 {
287 fprintf(file, "int ");
288 }
289
290 if ((giArch == ARCH_X86) &&
292 {
293 fprintf(file, "__stdcall ");
294 }
295
296 /* Check for C++ */
297 if (pexp->strName.buf[0] == '?')
298 {
299 fprintf(file, "stub_function%d(", pexp->nNumber);
300 }
301 else
302 {
303 if (!bRelay || bInPrototype)
304 fprintf(file, "%.*s(", pexp->strName.len, pexp->strName.buf);
305 else
306 fprintf(file, "$relaytrace$%.*s(", pexp->strName.len, pexp->strName.buf);
307 }
308
309 for (i = 0; i < pexp->nArgCount; i++)
310 {
311 if (i != 0) fprintf(file, ", ");
312 switch (pexp->anArgs[i])
313 {
314 case ARG_LONG: fprintf(file, "long"); break;
315 case ARG_PTR: fprintf(file, "void*"); break;
316 case ARG_STR: fprintf(file, "char*"); break;
317 case ARG_WSTR: fprintf(file, "wchar_t*"); break;
318 case ARG_DBL: fprintf(file, "double"); break;
319 case ARG_INT64: fprintf(file, "__int64"); break;
320 /* __int128 is not supported on x86, so use a custom type */
321 case ARG_INT128: fprintf(file, "MyInt128"); break;
322 case ARG_FLOAT: fprintf(file, "float"); break;
323 }
324 fprintf(file, " a%d", i);
325 }
326
327 if (bInPrototype)
328 {
329 fprintf(file, ");\n\n");
330 }
331 } while (bInPrototype--);
332
333 if (!bRelay)
334 {
335 fprintf(file, ")\n{\n\tDbgPrint(\"WARNING: calling stub %.*s(",
336 pexp->strName.len, pexp->strName.buf);
337 }
338 else
339 {
340 fprintf(file, ")\n{\n");
341 if (pexp->uFlags & FL_REGISTER)
342 {
343 /* No return value */
344 }
345 else if (pexp->uFlags & FL_RET64)
346 {
347 fprintf(file, "\t__int64 retval;\n");
348 }
349 else
350 {
351 fprintf(file, "\tint retval;\n");
352 }
353 fprintf(file, "\tif (TRACE_ON(relay))\n\t\tDPRINTF(\"%s: %.*s(",
354 pszDllName, pexp->strName.len, pexp->strName.buf);
355 }
356
357 for (i = 0; i < pexp->nArgCount; i++)
358 {
359 if (i != 0) fprintf(file, ",");
360 switch (pexp->anArgs[i])
361 {
362 case ARG_LONG: fprintf(file, "0x%%lx"); break;
363 case ARG_PTR: fprintf(file, "0x%%p"); break;
364 case ARG_STR: fprintf(file, "'%%s'"); break;
365 case ARG_WSTR: fprintf(file, "'%%ws'"); break;
366 case ARG_DBL: fprintf(file, "%%f"); break;
367 case ARG_INT64: fprintf(file, "0x%%\"PRIx64\""); break;
368 case ARG_INT128: fprintf(file, "0x%%\"PRIx64\"-0x%%\"PRIx64\""); break;
369 case ARG_FLOAT: fprintf(file, "%%f"); break;
370 }
371 }
372 fprintf(file, ")\\n\"");
373
374 for (i = 0; i < pexp->nArgCount; i++)
375 {
376 fprintf(file, ", ");
377 switch (pexp->anArgs[i])
378 {
379 case ARG_LONG: case ARG_PTR: case ARG_STR:
380 case ARG_WSTR: case ARG_DBL: case ARG_INT64:
381 fprintf(file, "a%d", i); break;
382 case ARG_INT128:
383 fprintf(file, "a%d.lower, a%d.upper", i, i); break;
384 case ARG_FLOAT:
385 fprintf(file, "a%d", i); break;
386 }
387 }
388 fprintf(file, ");\n");
389
390 if (pexp->nCallingConvention == CC_STUB)
391 {
392 fprintf(file, "\t__wine_spec_unimplemented_stub(\"%s\", __FUNCTION__);\n", pszDllName);
393 }
394 else if (bRelay)
395 {
396 if (pexp->uFlags & FL_REGISTER)
397 {
398 fprintf(file,"\t");
399 }
400 else
401 {
402 fprintf(file, "\tretval = ");
403 }
404 fprintf(file, "%.*s(", pexp->strName.len, pexp->strName.buf);
405
406 for (i = 0; i < pexp->nArgCount; i++)
407 {
408 if (i != 0) fprintf(file, ", ");
409 fprintf(file, "a%d", i);
410 }
411 fprintf(file, ");\n");
412 }
413
414 if (!bRelay)
415 fprintf(file, "\treturn 0;\n}\n\n");
416 else if ((pexp->uFlags & FL_REGISTER) == 0)
417 {
418 if (pexp->uFlags & FL_RET64)
419 {
420 fprintf(file, "\tif (TRACE_ON(relay))\n\t\tDPRINTF(\"%s: %.*s: retval = 0x%%\"PRIx64\"\\n\", retval);\n",
421 pszDllName, pexp->strName.len, pexp->strName.buf);
422 }
423 else
424 {
425 fprintf(file, "\tif (TRACE_ON(relay))\n\t\tDPRINTF(\"%s: %.*s: retval = 0x%%lx\\n\", retval);\n",
426 pszDllName, pexp->strName.len, pexp->strName.buf);
427 }
428 fprintf(file, "\treturn retval;\n}\n\n");
429 }
430
431 return 1;
432}
433
434void
436{
437 fprintf(file, "; File generated automatically, do not edit!\n\n");
438
439 if (giArch == ARCH_X86)
440 {
441 fprintf(file, ".586\n.model flat\n.code\n");
442 }
443 else if (giArch == ARCH_AMD64)
444 {
445 fprintf(file, ".code\n");
446 }
447 else if (giArch == ARCH_ARM || giArch == ARCH_ARM64)
448 {
449 fprintf(file, " AREA |.text|,ALIGN=2,CODE,READONLY\n\n");
450 }
451}
452
453void
454Output_stublabel(FILE *fileDest, char* pszSymbolName)
455{
456 if (giArch == ARCH_ARM || giArch == ARCH_ARM64)
457 {
458 fprintf(fileDest,
459 "\tEXPORT |%s| [FUNC]\n|%s|\n",
460 pszSymbolName,
461 pszSymbolName);
462 }
463 else
464 {
465 fprintf(fileDest,
466 "PUBLIC %s\n%s: nop\n",
467 pszSymbolName,
468 pszSymbolName);
469 }
470}
471
472int
474{
475 char szNameBuffer[128];
476
477 /* Handle autoname */
478 if (pexp->strName.len == 1 && pexp->strName.buf[0] == '@')
479 {
480 sprintf(szNameBuffer, "%s_stub_ordinal%d",
481 gpszUnderscore, pexp->nOrdinal);
482 }
483 else if (giArch != ARCH_X86)
484 {
485 /* Does the string already have stdcall decoration? */
486 const char *pcAt = ScanToken(pexp->strName.buf, '@');
487 if (pcAt && (pcAt < (pexp->strName.buf + pexp->strName.len)) &&
488 (pexp->strName.buf[0] == '_'))
489 {
490 /* Skip leading underscore and remove trailing decoration */
491 sprintf(szNameBuffer, "_stub_%.*s",
492 (int)(pcAt - pexp->strName.buf - 1),
493 pexp->strName.buf + 1);
494 }
495 else
496 {
497 sprintf(szNameBuffer, "_stub_%.*s",
498 pexp->strName.len, pexp->strName.buf);
499 }
500 }
501 else if (pexp->nCallingConvention == CC_STDCALL)
502 {
503 sprintf(szNameBuffer, "__stub_%.*s@%d",
504 pexp->strName.len, pexp->strName.buf, pexp->nStackBytes);
505 }
506 else if (pexp->nCallingConvention == CC_FASTCALL)
507 {
508 sprintf(szNameBuffer, "@_stub_%.*s@%d",
509 pexp->strName.len, pexp->strName.buf, pexp->nStackBytes);
510 }
511 else if ((pexp->nCallingConvention == CC_CDECL) ||
512 (pexp->nCallingConvention == CC_THISCALL) ||
513 (pexp->nCallingConvention == CC_EXTERN) ||
514 (pexp->nCallingConvention == CC_STUB))
515 {
516 sprintf(szNameBuffer, "__stub_%.*s",
517 pexp->strName.len, pexp->strName.buf);
518 }
519 else
520 {
521 fprintf(stderr, "Invalid calling convention");
522 return 0;
523 }
524
525 Output_stublabel(fileDest, szNameBuffer);
526
527 return 1;
528}
529
530void
531OutputHeader_def(FILE *file, char *libname)
532{
534 "; File generated automatically, do not edit!\n\n"
535 "NAME %s\n\n"
536 "EXPORTS\n",
537 libname);
538}
539
540void
541PrintName(FILE *fileDest, EXPORT *pexp, PSTRING pstr, int fDeco)
542{
543 const char *pcName = pstr->buf;
544 int nNameLength = pstr->len;
545 const char* pcDot, *pcAt;
546 char namebuffer[19];
547
548 if ((nNameLength == 1) && (pcName[0] == '@'))
549 {
550 sprintf(namebuffer, "ordinal%d", pexp->nOrdinal);
551 pcName = namebuffer;
552 nNameLength = strlen(namebuffer);
553 }
554
555 /* Check for non-x86 first */
556 if (giArch != ARCH_X86)
557 {
558 /* Does the string already have stdcall decoration? */
559 pcAt = ScanToken(pcName, '@');
560 if (pcAt && (pcAt < (pcName + nNameLength)) && (pcName[0] == '_'))
561 {
562 /* Skip leading underscore and remove trailing decoration */
563 pcName++;
564 nNameLength = (int)(pcAt - pcName);
565 }
566
567 /* Print the undecorated function name */
568 fprintf(fileDest, "%.*s", nNameLength, pcName);
569 }
570 else if (fDeco &&
571 ((pexp->nCallingConvention == CC_STDCALL) ||
573 {
574 /* Beware with C++ exports */
575 int is_cpp = pcName[0] == '?';
576
577 /* Scan for a dll forwarding dot */
578 pcDot = ScanToken(pcName, '.');
579 if (pcDot)
580 {
581 /* First print the dll name, followed by a dot */
582 nNameLength = (int)(pcDot - pcName);
583 fprintf(fileDest, "%.*s.", nNameLength, pcName);
584
585 /* Now the actual function name */
586 pcName = pcDot + 1;
587 nNameLength = pexp->strTarget.len - nNameLength - 1;
588 }
589
590 /* Does the string already have decoration? */
591 pcAt = ScanToken(pcName, '@');
592 if (pcAt && (pcAt < (pcName + nNameLength)))
593 {
594 /* On GCC, we need to remove the leading stdcall underscore, but not for C++ exports */
595 if (!gbMSComp && !is_cpp && (pexp->nCallingConvention == CC_STDCALL))
596 {
597 pcName++;
598 nNameLength--;
599 }
600
601 /* Print the already decorated function name */
602 fprintf(fileDest, "%.*s", nNameLength, pcName);
603 }
604 else
605 {
606 /* Print the prefix, but skip it for (GCC && stdcall) */
607 if (gbMSComp || (pexp->nCallingConvention != CC_STDCALL))
608 {
609 fprintf(fileDest, "%c", pexp->nCallingConvention == CC_FASTCALL ? '@' : '_');
610 }
611
612 /* Print the name with trailing decoration */
613 fprintf(fileDest, "%.*s@%d", nNameLength, pcName, pexp->nStackBytes);
614 }
615 }
616 else if (fDeco && (pexp->nCallingConvention == CC_CDECL) && gbMSComp)
617 {
618 /* Print with cdecl decoration */
619 fprintf(fileDest, "_%.*s", nNameLength, pcName);
620 }
621 else
622 {
623 /* Print the undecorated function name */
624 fprintf(fileDest, "%.*s", nNameLength, pcName);
625 }
626}
627
628void
630{
631 PrintName(fileDest, pexp, &pexp->strName, 0);
632
633 if (gbImportLib)
634 {
635 /* Redirect to a stub function, to get the right decoration in the lib */
636 fprintf(fileDest, "=_stub_");
637 PrintName(fileDest, pexp, &pexp->strName, 0);
638 }
639 else if (pexp->strTarget.buf)
640 {
641 if (pexp->strName.buf[0] == '?')
642 {
643 //fprintf(stderr, "warning: ignoring C++ redirection %.*s -> %.*s\n",
644 // pexp->strName.len, pexp->strName.buf, pexp->strTarget.len, pexp->strTarget.buf);
645 }
646 else
647 {
648 fprintf(fileDest, "=");
649
650 /* If the original name was decorated, use decoration in the forwarder as well */
651 if ((giArch == ARCH_X86) && ScanToken(pexp->strName.buf, '@') &&
652 !ScanToken(pexp->strTarget.buf, '@') &&
653 ((pexp->nCallingConvention == CC_STDCALL) ||
654 (pexp->nCallingConvention == CC_FASTCALL)) )
655 {
656 PrintName(fileDest, pexp, &pexp->strTarget, 1);
657 }
658 else
659 {
660 /* Write the undecorated redirection name */
661 fprintf(fileDest, "%.*s", pexp->strTarget.len, pexp->strTarget.buf);
662 }
663 }
664 }
665 else if (((pexp->uFlags & FL_STUB) || (pexp->nCallingConvention == CC_STUB)) &&
666 (pexp->strName.buf[0] == '?'))
667 {
668 /* C++ stubs are forwarded to C stubs */
669 fprintf(fileDest, "=stub_function%d", pexp->nNumber);
670 }
671 else if (gbTracing && ((pexp->uFlags & FL_NORELAY) == 0) && (pexp->nCallingConvention == CC_STDCALL) &&
672 (pexp->strName.buf[0] != '?'))
673 {
674 /* Redirect it to the relay-tracing trampoline */
675 fprintf(fileDest, "=$relaytrace$%.*s", pexp->strName.len, pexp->strName.buf);
676 }
677}
678
679void
681{
682 int bTracing = 0;
683 /* Print the function name, with decoration for export libs */
684 PrintName(fileDest, pexp, &pexp->strName, gbImportLib);
685 DbgPrint("Generating def line for '%.*s'\n", pexp->strName.len, pexp->strName.buf);
686
687 /* Check if this is a forwarded export */
688 if (pexp->strTarget.buf)
689 {
690 int fIsExternal = !!ScanToken(pexp->strTarget.buf, '.');
691 DbgPrint("Got redirect '%.*s'\n", pexp->strTarget.len, pexp->strTarget.buf);
692
693 /* print the target name, don't decorate if it is external */
694 fprintf(fileDest, pexp->uFlags & FL_IMPSYM ? "==" : "=");
695 PrintName(fileDest, pexp, &pexp->strTarget, !fIsExternal);
696 }
697 else if (((pexp->uFlags & FL_STUB) || (pexp->nCallingConvention == CC_STUB)) &&
698 (pexp->strName.buf[0] == '?'))
699 {
700 /* C++ stubs are forwarded to C stubs */
701 fprintf(fileDest, "=stub_function%d", pexp->nNumber);
702 }
703 else if (gbTracing && ((pexp->uFlags & FL_NORELAY) == 0) &&
704 (pexp->nCallingConvention == CC_STDCALL) &&
705 (pexp->strName.buf[0] != '?'))
706 {
707 /* Redirect it to the relay-tracing trampoline */
708 char buf[256];
709 STRING strTarget;
710 fprintf(fileDest, "=");
711 sprintf(buf, "$relaytrace$%.*s", pexp->strName.len, pexp->strName.buf);
712 strTarget.buf = buf;
713 strTarget.len = pexp->strName.len + 12;
714 PrintName(fileDest, pexp, &strTarget, 1);
715 bTracing = 1;
716 }
717
718 /* Special handling for stdcall and fastcall, but not C++ exports*/
719 if ((giArch == ARCH_X86) &&
720 (pexp->strName.buf[0] != '?') &&
721 ((pexp->nCallingConvention == CC_STDCALL) ||
723 {
724 /* Is this the import lib? */
725 if (gbImportLib)
726 {
727 /* Is the name in the spec file decorated? */
728 const char* pcDeco = ScanToken(pexp->strName.buf, '@');
729 if (pcDeco &&
730 (pexp->strName.len > 1) &&
731 (pcDeco < pexp->strName.buf + pexp->strName.len))
732 {
733 /* Write the name including the leading @ */
734 fprintf(fileDest, "==%.*s", pexp->strName.len, pexp->strName.buf);
735 }
736 }
737 else if ((!pexp->strTarget.buf) && !(bTracing))
738 {
739 /* Write a forwarder to the actual decorated symbol */
740 fprintf(fileDest, "=");
741 PrintName(fileDest, pexp, &pexp->strName, 1);
742 }
743 }
744}
745
746int
747OutputLine_def(FILE *fileDest, EXPORT *pexp)
748{
749 /* Don't add private exports to the import lib */
750 if (gbImportLib && (pexp->uFlags & FL_PRIVATE))
751 {
752 DbgPrint("OutputLine_def: skipping private export '%.*s'...\n", pexp->strName.len, pexp->strName.buf);
753 return 1;
754 }
755
756 /* Handle import symbols */
757 if (pexp->uFlags & FL_IMPSYM)
758 {
759 /* Skip these, if we are not creating an import lib, or if this is MS */
760 if (!gbImportLib || gbMSComp)
761 {
762 DbgPrint("OutputLine_def: skipping import symbol '%.*s'...\n", pexp->strName.len, pexp->strName.buf);
763 return 1;
764 }
765 }
766
767 /* For MS linker, forwarded externs are managed via #pragma comment(linker,"/export:_data=org.data,DATA") */
768 if (gbMSComp && !gbImportLib && (pexp->nCallingConvention == CC_EXTERN) &&
769 (pexp->strTarget.buf != NULL) && !!ScanToken(pexp->strTarget.buf, '.'))
770 {
771 DbgPrint("OutputLine_def: skipping forwarded extern export '%.*s' ->'%.*s'...\n",
772 pexp->strName.len, pexp->strName.buf, pexp->strTarget.len, pexp->strTarget.buf);
773 return 1;
774 }
775
776 DbgPrint("OutputLine_def: '%.*s'...\n", pexp->strName.len, pexp->strName.buf);
777 fprintf(fileDest, " ");
778
779 if (gbMSComp)
780 OutputLine_def_MS(fileDest, pexp);
781 else
782 OutputLine_def_GCC(fileDest, pexp);
783
784 /* On GCC builds we force ordinals */
785 if ((pexp->uFlags & FL_ORDINAL) || (!gbMSComp && !gbImportLib))
786 {
787 fprintf(fileDest, " @%d", pexp->nOrdinal);
788 }
789
790 if (pexp->uFlags & FL_NONAME)
791 {
792 fprintf(fileDest, " NONAME");
793 }
794
795 /* Either PRIVATE or DATA */
796 if (pexp->uFlags & FL_PRIVATE)
797 {
798 fprintf(fileDest, " PRIVATE");
799 }
800 else if (pexp->nCallingConvention == CC_EXTERN)
801 {
802 fprintf(fileDest, " DATA");
803 }
804
805 fprintf(fileDest, "\n");
806
807 return 1;
808}
809
810void
811PrintNameOrImpName(FILE *fileDest, EXPORT *pexp, PSTRING pstr, int fDeco, int fImp)
812{
813 if (fImp)
814 {
815 fprintf(fileDest, "__imp_");
816 }
817
818 PrintName(fileDest, pexp, pstr, fDeco);
819}
820
821void
822OutputAlias(FILE *fileDest, EXPORT *pexp, int fImp)
823{
824 if ((giArch == ARCH_ARM) || (giArch == ARCH_ARM64))
825 {
826 fprintf(fileDest, " IMPORT ");
827 PrintNameOrImpName(fileDest, pexp, &pexp->strName, 1, fImp);
828 fprintf(fileDest, ", WEAK ");
829 PrintNameOrImpName(fileDest, pexp, &pexp->strTarget, 1, fImp);
830 fprintf(fileDest, "\n");
831 }
832 else
833 {
834 fprintf(fileDest, " EXTERN ");
835 PrintNameOrImpName(fileDest, pexp, &pexp->strTarget, 1, fImp);
836 fprintf(fileDest, ":PROC\n ALIAS <");
837 PrintNameOrImpName(fileDest, pexp, &pexp->strName, 1, fImp);
838 fprintf(fileDest, "> = <");
839 PrintNameOrImpName(fileDest, pexp, &pexp->strTarget, 1, fImp);
840 fprintf(fileDest, ">\n");
841 }
842}
843
844int
846{
847 if ((pexp->uFlags & FL_IMPSYM) == 0)
848 {
849 return 1;
850 }
851
852 OutputAlias(fileDest, pexp, 0);
853 OutputAlias(fileDest, pexp, 1);
854
855 return 1;
856}
857
858void
860 const char* filename,
861 unsigned nLine,
862 const char *pcLine,
863 const char *pc,
864 size_t errorlen,
865 const char *format,
866 va_list argptr)
867{
868 unsigned i, errorpos, len;
869 const char* pcLineEnd;
870
871 /* Get the length of the line */
872 pcLineEnd = strpbrk(pcLine, "\r\n");
873 len = (unsigned)(pcLineEnd - pcLine);
874
875 if (pc == NULL)
876 {
877 pc = pcLine + len - 1;
878 errorlen = 1;
879 }
880
881 errorpos = (unsigned)(pc - pcLine);
882
883 /* Output the error message */
884 fprintf(stderr, "ERROR: (%s:%u:%u): ", filename, nLine, errorpos);
885 vfprintf(stderr, format, argptr);
886 fprintf(stderr, "\n");
887
888 /* Output the line with the error */
889 fprintf(stderr, "> %.*s\n", len, pcLine);
890
891 if (errorlen == 0)
892 {
893 errorlen = TokenLength(pc);
894 }
895
896 for (i = 0; i < errorpos + 2; i++)
897 {
898 fprintf(stderr, " ");
899 }
900 for (i = 0; i < errorlen; i++)
901 {
902 fprintf(stderr, "~");
903 }
904 fprintf(stderr, "\n");
905 exit(-1);
906}
907
908void
910 const char* filename,
911 unsigned nLine,
912 const char *pcLine,
913 const char *pc,
914 size_t errorlen,
915 const char *format,
916 ...)
917{
918 va_list argptr;
919
920 va_start(argptr, format);
921 Fatalv(filename, nLine, pcLine, pc, errorlen, format, argptr);
922 va_end(argptr);
923}
924
925EXPORT *
926ParseFile(char* pcStart, FILE *fileDest, unsigned *cExports)
927{
928 EXPORT *pexports;
929 const char *pc, *pcLine;
930 int cLines, nLine;
931 EXPORT exp;
932 int included;
933 unsigned int i;
934
935 *cExports = 0;
936
937 //fprintf(stderr, "info: line %d, pcStart:'%.30s'\n", nLine, pcStart);
938
939 /* Count the lines */
940 for (cLines = 1, pcLine = pcStart; *pcLine; pcLine = NextLine(pcLine), cLines++)
941 {
942 /* Nothing */
943 }
944
945 /* Allocate an array of EXPORT structures */
946 pexports = malloc(cLines * sizeof(EXPORT));
947 if (pexports == NULL)
948 {
949 fprintf(stderr, "ERROR: %s: failed to allocate EXPORT array of %u elements\n", pszSourceFileName, cLines);
950 return NULL;
951 }
952
953 /* Loop all lines */
954 nLine = 1;
955 exp.nNumber = 0;
956 for (pcLine = pcStart; *pcLine; pcLine = NextLine(pcLine), nLine++)
957 {
958 pc = pcLine;
959
960 exp.strName.buf = NULL;
961 exp.strName.len = 0;
962 exp.strTarget.buf = NULL;
963 exp.strTarget.len = 0;
964 exp.nArgCount = 0;
965 exp.uFlags = 0;
966 exp.nNumber++;
967 exp.nStartVersion = 0;
968 exp.nEndVersion = 0xFFFFFFFF;
969 exp.bVersionIncluded = 1;
970
971 /* Skip white spaces */
972 while (*pc == ' ' || *pc == '\t') pc++;
973
974 /* Check for line break or comment */
975 if ((*pc == '\r') || (*pc == '\n') ||
976 (*pc == ';') || (*pc == '#'))
977 {
978 continue;
979 }
980
981 /* On EOF we are done */
982 if (*pc == 0)
983 {
984 return pexports;
985 }
986
987 /* Now we should get either an ordinal or @ */
988 if (*pc == '@')
989 {
990 exp.nOrdinal = -1;
991 }
992 else if ((*pc >= '0') && (*pc <= '9'))
993 {
994 char* end;
995 long int number = strtol(pc, &end, 10);
996 if ((*end != ' ') && (*end != '\t'))
997 {
998 Fatal(pszSourceFileName, nLine, pcLine, end, 0, "Unexpected character(s) after ordinal");
999 }
1000
1001 if ((number < 0) || (number > 0xFFFE))
1002 {
1003 Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Invalid value for ordinal");
1004 }
1005
1006 exp.nOrdinal = number;
1007
1008 /* The import lib should contain the ordinal only if -ordinal was specified */
1009 if (!gbImportLib)
1010 exp.uFlags |= FL_ORDINAL;
1011 }
1012 else
1013 {
1014 Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Expected '@' or ordinal");
1015 }
1016
1017 /* Go to next token (type) */
1018 if (!(pc = NextToken(pc)))
1019 {
1020 Fatal(pszSourceFileName, nLine, pcLine, pc, 1, "Unexpected end of line");
1021 }
1022
1023 //fprintf(stderr, "info: Token:'%.*s'\n", TokenLength(pc), pc);
1024
1025 /* Now we should get the type */
1026 if (CompareToken(pc, "stdcall"))
1027 {
1028 exp.nCallingConvention = CC_STDCALL;
1029 }
1030 else if (CompareToken(pc, "cdecl") ||
1031 CompareToken(pc, "varargs"))
1032 {
1033 exp.nCallingConvention = CC_CDECL;
1034 }
1035 else if (CompareToken(pc, "fastcall"))
1036 {
1037 exp.nCallingConvention = CC_FASTCALL;
1038 }
1039 else if (CompareToken(pc, "thiscall"))
1040 {
1041 exp.nCallingConvention = CC_THISCALL;
1042 }
1043 else if (CompareToken(pc, "extern"))
1044 {
1045 exp.nCallingConvention = CC_EXTERN;
1046 }
1047 else if (CompareToken(pc, "stub"))
1048 {
1049 exp.nCallingConvention = CC_STUB;
1050 }
1051 else
1052 {
1053 Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Invalid calling convention");
1054 }
1055
1056 /* Go to next token (options or name) */
1057 if (!(pc = NextToken(pc)))
1058 {
1059 Fatal(pszSourceFileName, nLine, pcLine, pc, 1, "Unexpected end of line");
1060 }
1061
1062 /* Handle options */
1063 included = 1;
1064 while (*pc == '-')
1065 {
1066 if (CompareToken(pc, "-arch="))
1067 {
1068 /* Default to not included */
1069 included = 0;
1070 pc += 5;
1071
1072 /* Look if we are included */
1073 do
1074 {
1075 pc++;
1076 if (CompareToken(pc, pszArchString) ||
1078 {
1079 included = 1;
1080 }
1081
1082 /* Skip to next arch or end */
1083 while (*pc > ',') pc++;
1084 } while (*pc == ',');
1085 }
1086 else if (CompareToken(pc, "-i386"))
1087 {
1088 if (giArch != ARCH_X86) included = 0;
1089 }
1090 else if (CompareToken(pc, "-version="))
1091 {
1092 const char *pcVersionStart = pc + 9;
1093
1094 /* Default to not included */
1095 exp.bVersionIncluded = 0;
1096 pc += 8;
1097
1098 /* Look if we are included */
1099 do
1100 {
1101 unsigned version, endversion;
1102
1103 /* Optionally skip leading '0x' */
1104 pc++;
1105 if ((pc[0] == '0') && (pc[1] == 'x')) pc += 2;
1106
1107 /* Now get the version number */
1108 endversion = version = strtoul(pc, (char**)&pc, 16);
1109
1110 /* Check if it's a range */
1111 if (pc[0] == '+')
1112 {
1113 endversion = 0xFFF;
1114 pc++;
1115 }
1116 else if (pc[0] == '-')
1117 {
1118 /* Optionally skip leading '0x' */
1119 pc++;
1120 if ((pc[0] == '0') && (pc[1] == 'x')) pc += 2;
1121 endversion = strtoul(pc, (char**)&pc, 16);
1122 }
1123
1124 /* Check for degenerate range */
1125 if (version > endversion)
1126 {
1128 nLine,
1129 pcLine,
1130 pcVersionStart,
1131 pc - pcVersionStart,
1132 "Invalid version range");
1133 }
1134
1135 exp.nStartVersion = version;
1136 exp.nEndVersion = endversion;
1137
1138 /* Now compare the range with our version */
1139 if ((guOsVersion >= version) &&
1140 (guOsVersion <= endversion))
1141 {
1142 exp.bVersionIncluded = 1;
1143 }
1144
1145 /* Skip to next arch or end */
1146 while (*pc > ',') pc++;
1147
1148 } while (*pc == ',');
1149 }
1150 else if (CompareToken(pc, "-private"))
1151 {
1152 exp.uFlags |= FL_PRIVATE;
1153 }
1154 else if (CompareToken(pc, "-noname"))
1155 {
1156 exp.uFlags |= FL_ORDINAL | FL_NONAME;
1157 }
1158 else if (CompareToken(pc, "-impsym"))
1159 {
1160 exp.uFlags |= FL_IMPSYM;
1161 }
1162 else if (CompareToken(pc, "-ordinal"))
1163 {
1164 exp.uFlags |= FL_ORDINAL;
1165 /* GCC doesn't automatically import by ordinal if an ordinal
1166 * is found in the def file. Force it. */
1167 if (gbImportLib && !gbMSComp)
1168 exp.uFlags |= FL_NONAME;
1169 }
1170 else if (CompareToken(pc, "-stub"))
1171 {
1172 exp.uFlags |= FL_STUB;
1173 }
1174 else if (CompareToken(pc, "-norelay"))
1175 {
1176 exp.uFlags |= FL_NORELAY;
1177 }
1178 else if (CompareToken(pc, "-ret64"))
1179 {
1180 exp.uFlags |= FL_RET64;
1181 }
1182 else if (CompareToken(pc, "-register"))
1183 {
1184 exp.uFlags |= FL_REGISTER;
1185 }
1186 else
1187 {
1189 "INFO: %s line %d: Ignored option: '%.*s'\n",
1191 nLine,
1192 TokenLength(pc),
1193 pc);
1194 }
1195
1196 /* Go to next token */
1197 pc = NextToken(pc);
1198 }
1199
1200 //fprintf(stderr, "info: Name:'%.10s'\n", pc);
1201
1202 /* If arch didn't match ours, skip this entry */
1203 if (!included) continue;
1204
1205 /* Get name */
1206 exp.strName.buf = pc;
1207 exp.strName.len = TokenLength(pc);
1208 //DbgPrint("Got name: '%.*s'\n", exp.strName.len, exp.strName.buf);
1209
1210 /* Check for autoname */
1211 if ((exp.strName.len == 1) && (exp.strName.buf[0] == '@'))
1212 {
1213 exp.uFlags |= FL_ORDINAL | FL_NONAME;
1214 }
1215
1216 /* Handle parameters */
1217 exp.nStackBytes = 0;
1218 pc = NextToken(pc);
1219 /* Extern can't have parameters, and it's optional to provide ones for stubs. All other exports must have them */
1220 if (!pc && (exp.nCallingConvention != CC_EXTERN && exp.nCallingConvention != CC_STUB))
1221 {
1222 Fatal(pszSourceFileName, nLine, pcLine, pc, 1, "Unexpected end of line");
1223 }
1224
1225 if (pc && (exp.nCallingConvention != CC_EXTERN))
1226 {
1227 /* Verify syntax */
1228 if (*pc++ != '(')
1229 {
1230 Fatal(pszSourceFileName, nLine, pcLine, pc - 1, 0, "Expected '('");
1231 }
1232
1233 /* Skip whitespaces */
1234 while (*pc == ' ' || *pc == '\t') pc++;
1235
1236 exp.nStackBytes = 0;
1237 while (*pc >= '0')
1238 {
1239 if (CompareToken(pc, "long"))
1240 {
1241 exp.nStackBytes += 4;
1242 exp.anArgs[exp.nArgCount] = ARG_LONG;
1243 }
1244 else if (CompareToken(pc, "double"))
1245 {
1246 exp.nStackBytes += 8;
1247 exp.anArgs[exp.nArgCount] = ARG_DBL;
1248 }
1249 else if (CompareToken(pc, "ptr"))
1250 {
1251 exp.nStackBytes += 4; // sizeof(void*) on x86
1252 exp.anArgs[exp.nArgCount] = ARG_PTR;
1253 }
1254 else if (CompareToken(pc, "str"))
1255 {
1256 exp.nStackBytes += 4; // sizeof(void*) on x86
1257 exp.anArgs[exp.nArgCount] = ARG_STR;
1258 }
1259 else if (CompareToken(pc, "wstr"))
1260 {
1261 exp.nStackBytes += 4; // sizeof(void*) on x86
1262 exp.anArgs[exp.nArgCount] = ARG_WSTR;
1263 }
1264 else if (CompareToken(pc, "int64"))
1265 {
1266 exp.nStackBytes += 8;
1267 exp.anArgs[exp.nArgCount] = ARG_INT64;
1268 }
1269 else if (CompareToken(pc, "int128"))
1270 {
1271 exp.nStackBytes += 16;
1272 exp.anArgs[exp.nArgCount] = ARG_INT128;
1273 }
1274 else if (CompareToken(pc, "float"))
1275 {
1276 exp.nStackBytes += 4;
1277 exp.anArgs[exp.nArgCount] = ARG_FLOAT;
1278 }
1279 else
1280 {
1281 Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Unrecognized type");
1282 }
1283
1284 exp.nArgCount++;
1285
1286 /* Go to next parameter */
1287 if (!(pc = NextToken(pc)))
1288 {
1289 Fatal(pszSourceFileName, nLine, pcLine, pc, 1, "Unexpected end of line");
1290 }
1291 }
1292
1293 /* Check syntax */
1294 if (*pc++ != ')')
1295 {
1296 Fatal(pszSourceFileName, nLine, pcLine, pc - 1, 0, "Expected ')'");
1297 }
1298
1299 /* Go to next token */
1300 pc = NextToken(pc);
1301 }
1302
1303 /* Handle special stub cases */
1304 if (exp.nCallingConvention == CC_STUB)
1305 {
1306 /* If we got parameters, assume STDCALL */
1307 if (exp.nArgCount != 0)
1308 {
1309 exp.nCallingConvention = CC_STDCALL;
1310 exp.uFlags |= FL_STUB;
1311 }
1312
1313 /* Check for c++ mangled name */
1314 if (exp.strName.buf[0] == '?')
1315 {
1316 //printf("Found c++ mangled name...\n");
1317 //
1318 }
1319 else
1320 {
1321 /* Check for stdcall name */
1322 const char *p = ScanToken(exp.strName.buf, '@');
1323 if (p && (p - exp.strName.buf < exp.strName.len))
1324 {
1325 int i;
1326
1327 /* Truncate the name to before the @ */
1328 exp.strName.len = (int)(p - exp.strName.buf);
1329 if (exp.strName.len < 1)
1330 {
1331 Fatal(pszSourceFileName, nLine, pcLine, p, 1, "Unexpected @");
1332 }
1333 exp.nStackBytes = atoi(p + 1);
1334 exp.nArgCount = exp.nStackBytes / 4;
1335 exp.nCallingConvention = CC_STDCALL;
1336 exp.uFlags |= FL_STUB;
1337 for (i = 0; i < exp.nArgCount; i++)
1338 exp.anArgs[i] = ARG_LONG;
1339 }
1340 }
1341 }
1342
1343 /* Check optional redirection */
1344 if (pc)
1345 {
1346 exp.strTarget.buf = pc;
1347 exp.strTarget.len = TokenLength(pc);
1348
1349 /* Check syntax (end of line) */
1350 if (NextToken(pc))
1351 {
1352 Fatal(pszSourceFileName, nLine, pcLine, NextToken(pc), 0, "Excess token(s) at end of definition");
1353 }
1354
1355 /* Don't relay-trace forwarded functions */
1356 exp.uFlags |= FL_NORELAY;
1357 }
1358 else
1359 {
1360 exp.strTarget.buf = NULL;
1361 exp.strTarget.len = 0;
1362 }
1363
1364 /* Check for no-name without ordinal */
1365 if ((exp.uFlags & FL_ORDINAL) && (exp.nOrdinal == -1))
1366 {
1367 Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Ordinal export without ordinal");
1368 }
1369
1370 /* Check for import symbol without target */
1371 if ((exp.uFlags & FL_IMPSYM) && (exp.strTarget.buf == NULL))
1372 {
1373 Fatal(pszSourceFileName, nLine, pcLine, pc, 1, "Import symbol without target");
1374 }
1375
1376 /*
1377 * Check for special handling of OLE exports, only when MSVC
1378 * is not used, since otherwise this is handled by MS LINK.EXE.
1379 */
1380 if (!gbMSComp)
1381 {
1382 /* Check whether the current export is not PRIVATE, or has an ordinal */
1383 int bIsNotPrivate = (!gbNotPrivateNoWarn && /*gbImportLib &&*/ !(exp.uFlags & FL_PRIVATE));
1384 int bHasOrdinal = (exp.uFlags & FL_ORDINAL);
1385
1386 /* Check whether the current export is an OLE export, in case any of these tests pass */
1387 if (bIsNotPrivate || bHasOrdinal)
1388 {
1389 for (i = 0; i < ARRAYSIZE(astrOlePrivateExports); ++i)
1390 {
1391 if (strlen(astrOlePrivateExports[i]) == exp.strName.len &&
1392 strncmp(exp.strName.buf, astrOlePrivateExports[i], exp.strName.len) == 0)
1393 {
1394 /* The current export is an OLE export: display the corresponding warning */
1395 if (bIsNotPrivate)
1396 {
1397 fprintf(stderr, "WARNING: %s line %d: Exported symbol '%.*s' should be PRIVATE\n",
1398 pszSourceFileName, nLine, exp.strName.len, exp.strName.buf);
1399 }
1400 if (bHasOrdinal)
1401 {
1402 fprintf(stderr, "WARNING: %s line %d: exported symbol '%.*s' should not be assigned an ordinal\n",
1403 pszSourceFileName, nLine, exp.strName.len, exp.strName.buf);
1404 }
1405 break;
1406 }
1407 }
1408 }
1409 }
1410
1411 pexports[*cExports] = exp;
1412 (*cExports)++;
1413 gbDebug = 0;
1414 }
1415
1416 return pexports;
1417}
1418
1419int
1420ApplyOrdinals(EXPORT* pexports, unsigned cExports)
1421{
1422 unsigned short i, j;
1423 char* used;
1424
1425 /* Allocate a table to mark used ordinals */
1426 used = malloc(65536);
1427 if (used == NULL)
1428 {
1429 fprintf(stderr, "Failed to allocate memory for ordinal use table\n");
1430 return -1;
1431 }
1432 memset(used, 0, 65536);
1433
1434 /* Pass 1: mark the ordinals that are already used */
1435 for (i = 0; i < cExports; i++)
1436 {
1437 if (pexports[i].uFlags & FL_ORDINAL)
1438 {
1439 if (used[pexports[i].nOrdinal] != 0)
1440 {
1441 fprintf(stderr, "Found duplicate ordinal: %u\n", pexports[i].nOrdinal);
1442 return -1;
1443 }
1444 used[pexports[i].nOrdinal] = 1;
1445 }
1446 }
1447
1448 /* Pass 2: apply available ordinals */
1449 for (i = 0, j = 1; i < cExports; i++)
1450 {
1451 if ((pexports[i].uFlags & FL_ORDINAL) == 0 && pexports[i].bVersionIncluded)
1452 {
1453 while (used[j] != 0)
1454 j++;
1455
1456 pexports[i].nOrdinal = j;
1457 used[j] = 1;
1458 }
1459 }
1460
1461 free(used);
1462 return 0;
1463}
1464
1465void usage(void)
1466{
1467 printf("syntax: spec2def [<options> ...] <spec file>\n"
1468 "Possible options:\n"
1469 " -h --help print this help screen\n"
1470 " -l=<file> generate an asm lib stub\n"
1471 " -d=<file> generate a def file\n"
1472 " -s=<file> generate a stub file\n"
1473 " -i=<file> generate an import alias file\n"
1474 " --ms MSVC compatibility\n"
1475 " -n=<name> name of the dll\n"
1476 " --version=<version> Sets the version to create exports for\n"
1477 " --implib generate a def file for an import library\n"
1478 " --no-private-warnings suppress warnings about symbols that should be -private\n"
1479 " -a=<arch> set architecture to <arch> (i386, x86_64, arm, arm64)\n"
1480 " --with-tracing generate wine-like \"+relay\" trace trampolines (needs -s)\n");
1481}
1482
1483int main(int argc, char *argv[])
1484{
1485 size_t nFileSize;
1486 char *pszSource, *pszDefFileName = NULL, *pszStubFileName = NULL, *pszLibStubName = NULL;
1487 char *pszImpLibAliasFileName = NULL;
1488 const char* pszVersionOption = "--version=0x";
1489 char achDllName[40];
1490 FILE *file;
1491 unsigned cExports = 0, i;
1492 EXPORT *pexports;
1493
1494 if (argc < 2)
1495 {
1496 usage();
1497 return -1;
1498 }
1499
1500 /* Read options */
1501 for (i = 1; i < (unsigned)argc && *argv[i] == '-'; i++)
1502 {
1503 if ((strcasecmp(argv[i], "--help") == 0) ||
1504 (strcasecmp(argv[i], "-h") == 0))
1505 {
1506 usage();
1507 return 0;
1508 }
1509 else if (argv[i][1] == 'd' && argv[i][2] == '=')
1510 {
1511 pszDefFileName = argv[i] + 3;
1512 }
1513 else if (argv[i][1] == 'l' && argv[i][2] == '=')
1514 {
1515 pszLibStubName = argv[i] + 3;
1516 }
1517 else if (argv[i][1] == 's' && argv[i][2] == '=')
1518 {
1519 pszStubFileName = argv[i] + 3;
1520 }
1521 else if (argv[i][1] == 'i' && argv[i][2] == '=')
1522 {
1523 pszImpLibAliasFileName = argv[i] + 3;
1524 }
1525 else if (argv[i][1] == 'n' && argv[i][2] == '=')
1526 {
1527 pszDllName = argv[i] + 3;
1528 }
1529 else if (strncasecmp(argv[i], pszVersionOption, strlen(pszVersionOption)) == 0)
1530 {
1531 guOsVersion = strtoul(argv[i] + strlen(pszVersionOption), NULL, 16);
1532 }
1533 else if (strcasecmp(argv[i], "--implib") == 0)
1534 {
1535 gbImportLib = 1;
1536 }
1537 else if (strcasecmp(argv[i], "--ms") == 0)
1538 {
1539 gbMSComp = 1;
1540 }
1541 else if (strcasecmp(argv[i], "--no-private-warnings") == 0)
1542 {
1544 }
1545 else if (strcasecmp(argv[i], "--with-tracing") == 0)
1546 {
1547 if (!pszStubFileName)
1548 {
1549 fprintf(stderr, "Error: cannot use --with-tracing without -s option.\n");
1550 return -1;
1551 }
1552 gbTracing = 1;
1553 }
1554 else if (argv[i][1] == 'a' && argv[i][2] == '=')
1555 {
1556 pszArchString = argv[i] + 3;
1557 }
1558 else
1559 {
1560 fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
1561 return -1;
1562 }
1563 }
1564
1565 if (strcasecmp(pszArchString, "i386") == 0)
1566 {
1567 giArch = ARCH_X86;
1568 gpszUnderscore = "_";
1569 }
1570 else if (strcasecmp(pszArchString, "x86_64") == 0) giArch = ARCH_AMD64;
1571 else if (strcasecmp(pszArchString, "ia64") == 0) giArch = ARCH_IA64;
1572 else if (strcasecmp(pszArchString, "arm") == 0) giArch = ARCH_ARM;
1573 else if (strcasecmp(pszArchString, "arm64") == 0) giArch = ARCH_ARM64;
1574 else if (strcasecmp(pszArchString, "ppc") == 0) giArch = ARCH_PPC;
1575
1576 if ((giArch == ARCH_AMD64) || (giArch == ARCH_IA64))
1577 {
1578 pszArchString2 = "win64";
1579 }
1580 else
1581 pszArchString2 = "win32";
1582
1583 /* Set a default dll name */
1584 if (!pszDllName)
1585 {
1586 char *p1, *p2;
1587 size_t len;
1588
1589 p1 = strrchr(argv[i], '\\');
1590 if (!p1) p1 = strrchr(argv[i], '/');
1591 p2 = p1 = p1 ? p1 + 1 : argv[i];
1592
1593 /* walk up to '.' */
1594 while (*p2 != '.' && *p2 != 0) p2++;
1595 len = p2 - p1;
1596 if (len >= sizeof(achDllName) - 5)
1597 {
1598 fprintf(stderr, "name too long: %s\n", p1);
1599 return -2;
1600 }
1601
1602 strncpy(achDllName, p1, len);
1603 strncpy(achDllName + len, ".dll", sizeof(achDllName) - len);
1604 pszDllName = achDllName;
1605 }
1606
1607 /* Open input file */
1610 if (!file)
1611 {
1612 fprintf(stderr, "error: could not open file %s\n", pszSourceFileName);
1613 return -3;
1614 }
1615
1616 /* Get file size */
1617 fseek(file, 0, SEEK_END);
1618 nFileSize = ftell(file);
1619 rewind(file);
1620
1621 /* Allocate memory buffer */
1622 pszSource = malloc(nFileSize + 1);
1623 if (!pszSource)
1624 {
1625 fclose(file);
1626 return -4;
1627 }
1628
1629 /* Load input file into memory */
1630 nFileSize = fread(pszSource, 1, nFileSize, file);
1631 fclose(file);
1632
1633 /* Zero terminate the source */
1634 pszSource[nFileSize] = '\0';
1635
1636 pexports = ParseFile(pszSource, file, &cExports);
1637 if (pexports == NULL)
1638 {
1639 fprintf(stderr, "error: could not parse file!\n");
1640 return -1;
1641 }
1642
1643 if (!gbMSComp)
1644 {
1645 if (ApplyOrdinals(pexports, cExports) < 0)
1646 {
1647 fprintf(stderr, "error: could not apply ordinals!\n");
1648 return -1;
1649 }
1650 }
1651
1652 if (pszDefFileName)
1653 {
1654 /* Open output file */
1655 file = fopen(pszDefFileName, "w");
1656 if (!file)
1657 {
1658 fprintf(stderr, "error: could not open output file %s\n", pszDefFileName);
1659 return -5;
1660 }
1661
1663
1664 for (i = 0; i < cExports; i++)
1665 {
1666 if (pexports[i].bVersionIncluded)
1667 OutputLine_def(file, &pexports[i]);
1668 }
1669
1670 fclose(file);
1671 }
1672
1673 if (pszStubFileName)
1674 {
1675 /* Open output file */
1676 file = fopen(pszStubFileName, "w");
1677 if (!file)
1678 {
1679 fprintf(stderr, "error: could not open output file %s\n", pszStubFileName);
1680 return -5;
1681 }
1682
1684
1685 for (i = 0; i < cExports; i++)
1686 {
1687 if (pexports[i].bVersionIncluded)
1688 OutputLine_stub(file, &pexports[i]);
1689 }
1690
1691 fclose(file);
1692 }
1693
1694 if (pszLibStubName)
1695 {
1696 /* Open output file */
1697 file = fopen(pszLibStubName, "w");
1698 if (!file)
1699 {
1700 fprintf(stderr, "error: could not open output file %s\n", pszLibStubName);
1701 return -5;
1702 }
1703
1705
1706 for (i = 0; i < cExports; i++)
1707 {
1708 if (pexports[i].bVersionIncluded)
1709 OutputLine_asmstub(file, &pexports[i]);
1710 }
1711
1712 fprintf(file, "\n END\n");
1713 fclose(file);
1714 }
1715
1716 if (pszImpLibAliasFileName)
1717 {
1718 /* Open output file */
1719 file = fopen(pszImpLibAliasFileName, "w");
1720 if (!file)
1721 {
1722 fprintf(stderr, "error: could not open output file %s\n", pszImpLibAliasFileName);
1723 return -5;
1724 }
1725
1727
1728 for (i = 0; i < cExports; i++)
1729 {
1730 if (pexports[i].bVersionIncluded)
1731 OutputLine_implib_asm(file, &pexports[i]);
1732 }
1733
1734 fprintf(file, "\n END\n");
1735 fclose(file);
1736 }
1737
1738 free(pexports);
1739
1740 return 0;
1741}
static int argc
Definition: ServiceArgs.c:12
UINT32 strtoul(const char *String, char **Terminator, UINT32 Base)
Definition: utclib.c:696
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
char * strncpy(char *DstString, const char *SrcString, ACPI_SIZE Count)
Definition: utclib.c:427
char * strpbrk(const char *String, const char *Delimiters)
Definition: utclib.c:302
char * va_list
Definition: acmsvcex.h:78
#define va_end(ap)
Definition: acmsvcex.h:90
#define va_start(ap, A)
Definition: acmsvcex.h:91
static int used
Definition: adh-main.c:39
#define SEEK_END
Definition: cabinet.c:29
#define free
Definition: debug_ros.c:5
#define malloc
Definition: debug_ros.c:4
#define NULL
Definition: types.h:112
UINT uFlags
Definition: api.c:59
static const WCHAR version[]
Definition: asmname.c:66
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
int main()
Definition: test.c:6
#define strncasecmp
Definition: fake.h:10
#define strcasecmp
Definition: fake.h:9
std::wstring STRING
Definition: fontsub.cpp:33
#define printf
Definition: freeldr.h:97
GLuint GLuint end
Definition: gl.h:1545
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLfloat GLfloat p
Definition: glext.h:8902
GLenum GLsizei len
Definition: glext.h:6722
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat token
Definition: glfuncs.h:210
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
#define stdout
Definition: stdio.h:99
_CRTIMP void __cdecl rewind(_Inout_ FILE *_File)
#define stderr
Definition: stdio.h:100
_Check_return_opt_ _CRTIMP int __cdecl fprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format,...)
_Check_return_opt_ _CRTIMP int __cdecl vfprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format, va_list _ArgList)
_Check_return_opt_ _CRTIMP size_t __cdecl fread(_Out_writes_bytes_(_ElementSize *_Count) void *_DstBuf, _In_ size_t _ElementSize, _In_ size_t _Count, _Inout_ FILE *_File)
_Check_return_ _CRTIMP FILE *__cdecl fopen(_In_z_ const char *_Filename, _In_z_ const char *_Mode)
_Check_return_opt_ _CRTIMP int __cdecl fseek(_Inout_ FILE *_File, _In_ long _Offset, _In_ int _Origin)
_Check_return_opt_ _CRTIMP int __cdecl fclose(_Inout_ FILE *_File)
_Check_return_ _CRTIMP long __cdecl ftell(_Inout_ FILE *_File)
_Check_return_ int __cdecl atoi(_In_z_ const char *_Str)
_Check_return_ long __cdecl strtol(_In_z_ const char *_Str, _Out_opt_ _Deref_post_z_ char **_EndPtr, _In_ int _Radix)
const char * filename
Definition: ioapi.h:137
#define sprintf(buf, format,...)
Definition: sprintf.c:55
static unsigned int number
Definition: dsound.c:1479
static unsigned(__cdecl *hash_bstr)(bstr_t s)
DWORD exp
Definition: msg.c:16058
#define argv
Definition: mplay32.c:18
_Check_return_ _CRTIMP _CONST_RETURN char *__cdecl strrchr(_In_z_ const char *_Str, _In_ int _Ch)
#define exit(n)
Definition: config.h:202
#define memset(x, y, z)
Definition: compat.h:39
unsigned guOsVersion
Definition: spec2def.c:76
const char * astrCallingConventions[]
Definition: spec2def.c:113
const char * NextLine(const char *pc)
Definition: spec2def.c:180
#define DbgPrint(...)
Definition: spec2def.c:77
int gbDebug
Definition: spec2def.c:75
struct _STRING * PSTRING
void OutputHeader_stub(FILE *file)
Definition: spec2def.c:220
void OutputLine_def_MS(FILE *fileDest, EXPORT *pexp)
Definition: spec2def.c:629
int OutputLine_stub(FILE *file, EXPORT *pexp)
Definition: spec2def.c:236
char * pszArchString2
Definition: spec2def.c:71
@ FL_PRIVATE
Definition: spec2def.c:81
@ FL_REGISTER
Definition: spec2def.c:87
@ FL_NONAME
Definition: spec2def.c:83
@ FL_IMPSYM
Definition: spec2def.c:88
@ FL_ORDINAL
Definition: spec2def.c:84
@ FL_RET64
Definition: spec2def.c:86
@ FL_NORELAY
Definition: spec2def.c:85
@ FL_STUB
Definition: spec2def.c:82
const char * NextToken(const char *pc)
Definition: spec2def.c:202
void OutputLine_def_GCC(FILE *fileDest, EXPORT *pexp)
Definition: spec2def.c:680
void OutputHeader_def(FILE *file, char *libname)
Definition: spec2def.c:531
char * pszSourceFileName
Definition: spec2def.c:72
int gbNotPrivateNoWarn
Definition: spec2def.c:67
void Fatal(const char *filename, unsigned nLine, const char *pcLine, const char *pc, size_t errorlen, const char *format,...)
Definition: spec2def.c:909
char * pszDllName
Definition: spec2def.c:73
int giArch
Definition: spec2def.c:69
int gbMSComp
Definition: spec2def.c:65
int CompareToken(const char *token, const char *comparand)
Definition: spec2def.c:155
const char * ScanToken(const char *token, char chr)
Definition: spec2def.c:169
@ CC_STUB
Definition: spec2def.c:98
@ CC_CDECL
Definition: spec2def.c:94
@ CC_STDCALL
Definition: spec2def.c:93
@ CC_FASTCALL
Definition: spec2def.c:95
@ CC_THISCALL
Definition: spec2def.c:96
@ CC_EXTERN
Definition: spec2def.c:97
void OutputHeader_asmstub(FILE *file, char *libname)
Definition: spec2def.c:435
int OutputLine_implib_asm(FILE *fileDest, EXPORT *pexp)
Definition: spec2def.c:845
static const char * astrOlePrivateExports[]
Definition: spec2def.c:127
_ARCH
Definition: spec2def.c:55
@ ARCH_IA64
Definition: spec2def.c:58
@ ARCH_AMD64
Definition: spec2def.c:57
@ ARCH_X86
Definition: spec2def.c:56
@ ARCH_ARM64
Definition: spec2def.c:60
@ ARCH_ARM
Definition: spec2def.c:59
@ ARCH_PPC
Definition: spec2def.c:61
#define ARRAYSIZE(a)
Definition: spec2def.c:12
void PrintNameOrImpName(FILE *fileDest, EXPORT *pexp, PSTRING pstr, int fDeco, int fImp)
Definition: spec2def.c:811
int TokenLength(const char *pc)
Definition: spec2def.c:192
int ApplyOrdinals(EXPORT *pexports, unsigned cExports)
Definition: spec2def.c:1420
int(* PFNOUTLINE)(FILE *, EXPORT *)
Definition: spec2def.c:64
@ ARG_DBL
Definition: spec2def.c:107
@ ARG_FLOAT
Definition: spec2def.c:110
@ ARG_LONG
Definition: spec2def.c:103
@ ARG_PTR
Definition: spec2def.c:104
@ ARG_INT64
Definition: spec2def.c:108
@ ARG_STR
Definition: spec2def.c:105
@ ARG_WSTR
Definition: spec2def.c:106
@ ARG_INT128
Definition: spec2def.c:109
struct _STRING STRING
int gbImportLib
Definition: spec2def.c:66
void Output_stublabel(FILE *fileDest, char *pszSymbolName)
Definition: spec2def.c:454
char * pszArchString
Definition: spec2def.c:70
void OutputAlias(FILE *fileDest, EXPORT *pexp, int fImp)
Definition: spec2def.c:822
int OutputLine_asmstub(FILE *fileDest, EXPORT *pexp)
Definition: spec2def.c:473
static int IsSeparator(char chr)
Definition: spec2def.c:148
void usage(void)
Definition: spec2def.c:1465
void Fatalv(const char *filename, unsigned nLine, const char *pcLine, const char *pc, size_t errorlen, const char *format, va_list argptr)
Definition: spec2def.c:859
int OutputLine_def(FILE *fileDest, EXPORT *pexp)
Definition: spec2def.c:747
int gbTracing
Definition: spec2def.c:68
EXPORT * ParseFile(char *pcStart, FILE *fileDest, unsigned *cExports)
Definition: spec2def.c:926
void PrintName(FILE *fileDest, EXPORT *pexp, PSTRING pstr, int fDeco)
Definition: spec2def.c:541
char * gpszUnderscore
Definition: spec2def.c:74
int bVersionIncluded
Definition: spec2def.c:33
int nNumber
Definition: spec2def.c:30
STRING strName
Definition: spec2def.c:22
int nCallingConvention
Definition: spec2def.c:24
STRING strTarget
Definition: spec2def.c:23
int nStackBytes
Definition: spec2def.c:26
int nOrdinal
Definition: spec2def.c:25
unsigned nStartVersion
Definition: spec2def.c:31
int anArgs[30]
Definition: spec2def.c:28
int nArgCount
Definition: spec2def.c:27
unsigned int uFlags
Definition: spec2def.c:29
unsigned nEndVersion
Definition: spec2def.c:32
const char * buf
Definition: spec2def.c:16
int len
Definition: spec2def.c:17
Definition: fci.c:127