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