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