ReactOS  0.4.15-dev-3316-g067ca88
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 
14 typedef struct _STRING
15 {
16  const char *buf;
17  int len;
18 } STRING, *PSTRING;
19 
20 typedef struct
21 {
25  int nOrdinal;
27  int nArgCount;
28  int anArgs[30];
29  unsigned int uFlags;
30  int nNumber;
31  unsigned nStartVersion;
32  unsigned nEndVersion;
34 } EXPORT;
35 
36 #if 0 // Debug helper function
37 void
38 PrintExport(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 
54 enum _ARCH
55 {
62 };
63 
64 typedef int (*PFNOUTLINE)(FILE *, EXPORT *);
65 int gbMSComp = 0;
66 int gbImportLib = 0;
68 int gbTracing = 0;
70 char *pszArchString = "i386";
73 char *pszDllName = NULL;
74 char *gpszUnderscore = "";
75 int gbDebug;
76 unsigned guOsVersion = 0x502;
77 #define DbgPrint(...) (!gbDebug || fprintf(stderr, __VA_ARGS__))
78 
79 enum
80 {
82  FL_STUB = 2,
83  FL_NONAME = 4,
85  FL_NORELAY = 16,
86  FL_RET64 = 32,
88 };
89 
90 enum
91 {
98 };
99 
100 enum
101 {
110 };
111 
112 const char* astrCallingConventions[] =
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  */
126 static 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 
145 static
146 int
147 IsSeparator(char chr)
148 {
149  return ((chr <= ',' && chr != '$' && chr != '#') ||
150  (chr >= ':' && chr < '?') );
151 }
152 
153 int
154 CompareToken(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 
167 const char *
168 ScanToken(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 
178 const char *
179 NextLine(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 
190 int
191 TokenLength(const char *pc)
192 {
193  int length = 0;
194 
195  while (!IsSeparator(*pc++)) length++;
196 
197  return length;
198 }
199 
200 const char *
201 NextToken(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 
218 void
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 
241 int
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 
440 void
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 
459 void
460 Output_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 
478 int
479 OutputLine_asmstub(FILE *fileDest, EXPORT *pexp)
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 
536 void
537 OutputHeader_def(FILE *file, char *libname)
538 {
539  fprintf(file,
540  "; File generated automatically, do not edit!\n\n"
541  "NAME %s\n\n"
542  "EXPORTS\n",
543  libname);
544 }
545 
546 void
547 PrintName(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) ||
578  (pexp->nCallingConvention == CC_FASTCALL)))
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 
629 void
630 OutputLine_def_MS(FILE *fileDest, EXPORT *pexp)
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 
680 void
681 OutputLine_def_GCC(FILE *fileDest, EXPORT *pexp)
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) ||
723  (pexp->nCallingConvention == CC_FASTCALL)))
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 
747 int
748 OutputLine_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 
800 void
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 
850 void
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 
867 EXPORT *
868 ParseFile(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  {
1126  fprintf(stdout,
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 
1351 int
1352 ApplyOrdinals(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 
1397 void 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 
1413 int 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  {
1468  gbNotPrivateNoWarn = 1;
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 */
1534  file = fopen(pszSourceFileName, "r");
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 }
void PrintName(FILE *fileDest, EXPORT *pexp, PSTRING pstr, int fDeco)
Definition: spec2def.c:547
static int argc
Definition: ServiceArgs.c:12
UINT32 strtoul(const char *String, char **Terminator, UINT32 Base)
Definition: utclib.c:696
int ApplyOrdinals(EXPORT *pexports, unsigned cExports)
Definition: spec2def.c:1352
STRING strName
Definition: spec2def.c:22
int nOrdinal
Definition: spec2def.c:25
#define strcasecmp
Definition: fake.h:9
int OutputLine_stub(FILE *file, EXPORT *pexp)
Definition: spec2def.c:242
void OutputHeader_stub(FILE *file)
Definition: spec2def.c:219
struct _STRING * PSTRING
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
char * strpbrk(const char *String, const char *Delimiters)
Definition: utclib.c:302
int gbNotPrivateNoWarn
Definition: spec2def.c:67
char * strncpy(char *DstString, const char *SrcString, ACPI_SIZE Count)
Definition: utclib.c:427
int nArgCount
Definition: spec2def.c:27
#define free
Definition: debug_ros.c:5
const char * NextLine(const char *pc)
Definition: spec2def.c:179
const char * NextToken(const char *pc)
Definition: spec2def.c:201
int gbDebug
Definition: spec2def.c:75
const char * astrCallingConventions[]
Definition: spec2def.c:112
_Check_return_ _CRTIMP _CONST_RETURN char *__cdecl strrchr(_In_z_ const char *_Str, _In_ int _Ch)
UINT uFlags
Definition: api.c:59
#define argv
Definition: mplay32.c:18
const char * filename
Definition: ioapi.h:135
int OutputLine_def(FILE *fileDest, EXPORT *pexp)
Definition: spec2def.c:748
void OutputLine_def_GCC(FILE *fileDest, EXPORT *pexp)
Definition: spec2def.c:681
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
FILE * stdout
int bVersionIncluded
Definition: spec2def.c:33
#define sprintf(buf, format,...)
Definition: sprintf.c:55
void OutputHeader_def(FILE *file, char *libname)
Definition: spec2def.c:537
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
int nCallingConvention
Definition: spec2def.c:24
unsigned nStartVersion
Definition: spec2def.c:31
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
#define ARRAYSIZE(a)
Definition: spec2def.c:12
int CompareToken(const char *token, const char *comparand)
Definition: spec2def.c:154
_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)
#define va_end(ap)
Definition: acmsvcex.h:90
void Fatal(const char *filename, unsigned nLine, const char *pcLine, const char *pc, size_t errorlen, const char *format,...)
Definition: spec2def.c:851
const char * ScanToken(const char *token, char chr)
Definition: spec2def.c:168
_Check_return_opt_ _CRTIMP int __cdecl fprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format,...)
static size_t double number
Definition: printf.c:69
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
struct _EXPORT EXPORT
GLenum GLuint GLenum GLsizei length
Definition: glext.h:5579
#define strncasecmp
Definition: fake.h:10
static const WCHAR version[]
Definition: asmname.c:66
_Check_return_opt_ _CRTIMP int __cdecl fseek(_Inout_ FILE *_File, _In_ long _Offset, _In_ int _Origin)
int(* PFNOUTLINE)(FILE *, EXPORT *)
Definition: spec2def.c:64
char * gpszUnderscore
Definition: spec2def.c:74
char * va_list
Definition: acmsvcex.h:78
static const char * astrOlePrivateExports[]
Definition: spec2def.c:126
int main(int argc, char *argv[])
Definition: spec2def.c:1413
_CRTIMP void __cdecl rewind(_Inout_ FILE *_File)
int len
Definition: spec2def.c:17
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
int gbMSComp
Definition: spec2def.c:65
c used
Definition: write.c:2857
const char file[]
Definition: icontest.c:11
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
unsigned nEndVersion
Definition: spec2def.c:32
va_start(ap, x)
void OutputHeader_asmstub(FILE *file, char *libname)
Definition: spec2def.c:441
int nNumber
Definition: spec2def.c:30
GLuint GLuint end
Definition: gl.h:1545
std::wstring STRING
Definition: fontsub.cpp:33
int giArch
Definition: spec2def.c:69
void Output_stublabel(FILE *fileDest, char *pszSymbolName)
Definition: spec2def.c:460
char * pszSourceFileName
Definition: spec2def.c:72
GLenum GLsizei len
Definition: glext.h:6722
_Check_return_opt_ _CRTIMP int __cdecl fclose(_Inout_ FILE *_File)
_Check_return_ _CRTIMP FILE *__cdecl fopen(_In_z_ const char *_Filename, _In_z_ const char *_Mode)
static int IsSeparator(char chr)
Definition: spec2def.c:147
_ARCH
Definition: spec2def.c:54
void usage(void)
Definition: spec2def.c:1397
const char * buf
Definition: spec2def.c:16
EXPORT * ParseFile(char *pcStart, FILE *fileDest, unsigned *cExports)
Definition: spec2def.c:868
unsigned int uFlags
Definition: spec2def.c:29
int nStackBytes
Definition: spec2def.c:26
int gbImportLib
Definition: spec2def.c:66
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
int TokenLength(const char *pc)
Definition: spec2def.c:191
#define NULL
Definition: types.h:112
DWORD exp
Definition: msg.c:16033
char * pszArchString2
Definition: spec2def.c:71
_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)
_Check_return_ _CRTIMP long __cdecl ftell(_Inout_ FILE *_File)
FILE * stderr
#define SEEK_END
Definition: cabinet.c:27
void OutputLine_def_MS(FILE *fileDest, EXPORT *pexp)
Definition: spec2def.c:630
#define malloc
Definition: debug_ros.c:4
STRING strTarget
Definition: spec2def.c:23
char * pszDllName
Definition: spec2def.c:73
void exit(int exitcode)
Definition: _exit.c:33
GLfloat GLfloat p
Definition: glext.h:8902
unsigned guOsVersion
Definition: spec2def.c:76
struct _STRING STRING
_Check_return_opt_ _CRTIMP int __cdecl vfprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format, va_list _ArgList)
#define memset(x, y, z)
Definition: compat.h:39
int gbTracing
Definition: spec2def.c:68
int anArgs[30]
Definition: spec2def.c:28
int OutputLine_asmstub(FILE *fileDest, EXPORT *pexp)
Definition: spec2def.c:479
static unsigned(__cdecl *hash_bstr)(bstr_t s)
#define DbgPrint(...)
Definition: spec2def.c:77
#define printf
Definition: config.h:203
char * pszArchString
Definition: spec2def.c:70
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
Definition: fci.c:126