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