ReactOS  0.4.15-dev-2359-g0dedb9b
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  /* Scan for a dll forwarding dot */
580  pcDot = ScanToken(pcName, '.');
581  if (pcDot)
582  {
583  /* First print the dll name, followed by a dot */
584  nNameLength = (int)(pcDot - pcName);
585  fprintf(fileDest, "%.*s.", nNameLength, pcName);
586 
587  /* Now the actual function name */
588  pcName = pcDot + 1;
589  nNameLength = pexp->strTarget.len - nNameLength - 1;
590  }
591 
592  /* Does the string already have decoration? */
593  pcAt = ScanToken(pcName, '@');
594  if (pcAt && (pcAt < (pcName + nNameLength)))
595  {
596  /* On GCC, we need to remove the leading stdcall underscore */
597  if (!gbMSComp && (pexp->nCallingConvention == CC_STDCALL))
598  {
599  pcName++;
600  nNameLength--;
601  }
602 
603  /* Print the already decorated function name */
604  fprintf(fileDest, "%.*s", nNameLength, pcName);
605  }
606  else
607  {
608  /* Print the prefix, but skip it for (GCC && stdcall) */
609  if (gbMSComp || (pexp->nCallingConvention != CC_STDCALL))
610  {
611  fprintf(fileDest, "%c", pexp->nCallingConvention == CC_FASTCALL ? '@' : '_');
612  }
613 
614  /* Print the name with trailing decoration */
615  fprintf(fileDest, "%.*s@%d", nNameLength, pcName, pexp->nStackBytes);
616  }
617  }
618  else
619  {
620  /* Print the undecorated function name */
621  fprintf(fileDest, "%.*s", nNameLength, pcName);
622  }
623 }
624 
625 void
626 OutputLine_def_MS(FILE *fileDest, EXPORT *pexp)
627 {
628  PrintName(fileDest, pexp, &pexp->strName, 0);
629 
630  if (gbImportLib)
631  {
632  /* Redirect to a stub function, to get the right decoration in the lib */
633  fprintf(fileDest, "=_stub_");
634  PrintName(fileDest, pexp, &pexp->strName, 0);
635  }
636  else if (pexp->strTarget.buf)
637  {
638  if (pexp->strName.buf[0] == '?')
639  {
640  //fprintf(stderr, "warning: ignoring C++ redirection %.*s -> %.*s\n",
641  // pexp->strName.len, pexp->strName.buf, pexp->strTarget.len, pexp->strTarget.buf);
642  }
643  else
644  {
645  fprintf(fileDest, "=");
646 
647  /* If the original name was decorated, use decoration in the forwarder as well */
648  if ((giArch == ARCH_X86) && ScanToken(pexp->strName.buf, '@') &&
649  !ScanToken(pexp->strTarget.buf, '@') &&
650  ((pexp->nCallingConvention == CC_STDCALL) ||
651  (pexp->nCallingConvention == CC_FASTCALL)) )
652  {
653  PrintName(fileDest, pexp, &pexp->strTarget, 1);
654  }
655  else
656  {
657  /* Write the undecorated redirection name */
658  fprintf(fileDest, "%.*s", pexp->strTarget.len, pexp->strTarget.buf);
659  }
660  }
661  }
662  else if (((pexp->uFlags & FL_STUB) || (pexp->nCallingConvention == CC_STUB)) &&
663  (pexp->strName.buf[0] == '?'))
664  {
665  /* C++ stubs are forwarded to C stubs */
666  fprintf(fileDest, "=stub_function%d", pexp->nNumber);
667  }
668  else if (gbTracing && ((pexp->uFlags & FL_NORELAY) == 0) && (pexp->nCallingConvention == CC_STDCALL) &&
669  (pexp->strName.buf[0] != '?'))
670  {
671  /* Redirect it to the relay-tracing trampoline */
672  fprintf(fileDest, "=$relaytrace$%.*s", pexp->strName.len, pexp->strName.buf);
673  }
674 }
675 
676 void
677 OutputLine_def_GCC(FILE *fileDest, EXPORT *pexp)
678 {
679  int bTracing = 0;
680  /* Print the function name, with decoration for export libs */
681  PrintName(fileDest, pexp, &pexp->strName, gbImportLib);
682  DbgPrint("Generating def line for '%.*s'\n", pexp->strName.len, pexp->strName.buf);
683 
684  /* Check if this is a forwarded export */
685  if (pexp->strTarget.buf)
686  {
687  int fIsExternal = !!ScanToken(pexp->strTarget.buf, '.');
688  DbgPrint("Got redirect '%.*s'\n", pexp->strTarget.len, pexp->strTarget.buf);
689 
690  /* print the target name, don't decorate if it is external */
691  fprintf(fileDest, "=");
692  PrintName(fileDest, pexp, &pexp->strTarget, !fIsExternal);
693  }
694  else if (((pexp->uFlags & FL_STUB) || (pexp->nCallingConvention == CC_STUB)) &&
695  (pexp->strName.buf[0] == '?'))
696  {
697  /* C++ stubs are forwarded to C stubs */
698  fprintf(fileDest, "=stub_function%d", pexp->nNumber);
699  }
700  else if (gbTracing && ((pexp->uFlags & FL_NORELAY) == 0) &&
701  (pexp->nCallingConvention == CC_STDCALL) &&
702  (pexp->strName.buf[0] != '?'))
703  {
704  /* Redirect it to the relay-tracing trampoline */
705  char buf[256];
706  STRING strTarget;
707  fprintf(fileDest, "=");
708  sprintf(buf, "$relaytrace$%.*s", pexp->strName.len, pexp->strName.buf);
709  strTarget.buf = buf;
710  strTarget.len = pexp->strName.len + 12;
711  PrintName(fileDest, pexp, &strTarget, 1);
712  bTracing = 1;
713  }
714 
715  /* Special handling for stdcall and fastcall */
716  if ((giArch == ARCH_X86) &&
717  ((pexp->nCallingConvention == CC_STDCALL) ||
718  (pexp->nCallingConvention == CC_FASTCALL)))
719  {
720  /* Is this the import lib? */
721  if (gbImportLib)
722  {
723  /* Is the name in the spec file decorated? */
724  const char* pcDeco = ScanToken(pexp->strName.buf, '@');
725  if (pcDeco &&
726  (pexp->strName.len > 1) &&
727  (pcDeco < pexp->strName.buf + pexp->strName.len))
728  {
729  /* Write the name including the leading @ */
730  fprintf(fileDest, "==%.*s", pexp->strName.len, pexp->strName.buf);
731  }
732  }
733  else if ((!pexp->strTarget.buf) && !(bTracing))
734  {
735  /* Write a forwarder to the actual decorated symbol */
736  fprintf(fileDest, "=");
737  PrintName(fileDest, pexp, &pexp->strName, 1);
738  }
739  }
740 }
741 
742 int
743 OutputLine_def(FILE *fileDest, EXPORT *pexp)
744 {
745  /* Don't add private exports to the import lib */
746  if (gbImportLib && (pexp->uFlags & FL_PRIVATE))
747  {
748  DbgPrint("OutputLine_def: skipping private export '%.*s'...\n", pexp->strName.len, pexp->strName.buf);
749  return 1;
750  }
751 
752  /* For MS linker, forwarded externs are managed via #pragma comment(linker,"/export:_data=org.data,DATA") */
753  if (gbMSComp && !gbImportLib && (pexp->nCallingConvention == CC_EXTERN) &&
754  (pexp->strTarget.buf != NULL) && !!ScanToken(pexp->strTarget.buf, '.'))
755  {
756  DbgPrint("OutputLine_def: skipping forwarded extern export '%.*s' ->'%.*s'...\n",
757  pexp->strName.len, pexp->strName.buf, pexp->strTarget.len, pexp->strTarget.buf);
758  return 1;
759  }
760 
761  DbgPrint("OutputLine_def: '%.*s'...\n", pexp->strName.len, pexp->strName.buf);
762  fprintf(fileDest, " ");
763 
764  if (gbMSComp)
765  OutputLine_def_MS(fileDest, pexp);
766  else
767  OutputLine_def_GCC(fileDest, pexp);
768 
769  /* On GCC builds we force ordinals */
770  if ((pexp->uFlags & FL_ORDINAL) || (!gbMSComp && !gbImportLib))
771  {
772  fprintf(fileDest, " @%d", pexp->nOrdinal);
773  }
774 
775  if (pexp->uFlags & FL_NONAME)
776  {
777  fprintf(fileDest, " NONAME");
778  }
779 
780  /* Either PRIVATE or DATA */
781  if (pexp->uFlags & FL_PRIVATE)
782  {
783  fprintf(fileDest, " PRIVATE");
784  }
785  else if (pexp->nCallingConvention == CC_EXTERN)
786  {
787  fprintf(fileDest, " DATA");
788  }
789 
790  fprintf(fileDest, "\n");
791 
792  return 1;
793 }
794 
795 void
797  const char* filename,
798  unsigned nLine,
799  const char *pcLine,
800  const char *pc,
801  size_t errorlen,
802  const char *format,
803  va_list argptr)
804 {
805  unsigned i, errorpos, len;
806  const char* pcLineEnd;
807 
808  /* Get the length of the line */
809  pcLineEnd = strpbrk(pcLine, "\r\n");
810  len = (unsigned)(pcLineEnd - pcLine);
811 
812  if (pc == NULL)
813  {
814  pc = pcLine + len - 1;
815  errorlen = 1;
816  }
817 
818  errorpos = (unsigned)(pc - pcLine);
819 
820  /* Output the error message */
821  fprintf(stderr, "ERROR: (%s:%u:%u): ", filename, nLine, errorpos);
822  vfprintf(stderr, format, argptr);
823  fprintf(stderr, "\n");
824 
825  /* Output the line with the error */
826  fprintf(stderr, "> %.*s\n", len, pcLine);
827 
828  if (errorlen == 0)
829  {
830  errorlen = TokenLength(pc);
831  }
832 
833  for (i = 0; i < errorpos + 2; i++)
834  {
835  fprintf(stderr, " ");
836  }
837  for (i = 0; i < errorlen; i++)
838  {
839  fprintf(stderr, "~");
840  }
841  fprintf(stderr, "\n");
842  exit(-1);
843 }
844 
845 void
847  const char* filename,
848  unsigned nLine,
849  const char *pcLine,
850  const char *pc,
851  size_t errorlen,
852  const char *format,
853  ...)
854 {
855  va_list argptr;
856 
857  va_start(argptr, format);
858  Fatalv(filename, nLine, pcLine, pc, errorlen, format, argptr);
859  va_end(argptr);
860 }
861 
862 EXPORT *
863 ParseFile(char* pcStart, FILE *fileDest, unsigned *cExports)
864 {
865  EXPORT *pexports;
866  const char *pc, *pcLine;
867  int cLines, nLine;
868  EXPORT exp;
869  int included;
870  unsigned int i;
871 
872  *cExports = 0;
873 
874  //fprintf(stderr, "info: line %d, pcStart:'%.30s'\n", nLine, pcStart);
875 
876  /* Count the lines */
877  for (cLines = 1, pcLine = pcStart; *pcLine; pcLine = NextLine(pcLine), cLines++)
878  {
879  /* Nothing */
880  }
881 
882  /* Allocate an array of EXPORT structures */
883  pexports = malloc(cLines * sizeof(EXPORT));
884  if (pexports == NULL)
885  {
886  fprintf(stderr, "ERROR: %s: failed to allocate EXPORT array of %u elements\n", pszSourceFileName, cLines);
887  return NULL;
888  }
889 
890  /* Loop all lines */
891  nLine = 1;
892  exp.nNumber = 0;
893  for (pcLine = pcStart; *pcLine; pcLine = NextLine(pcLine), nLine++)
894  {
895  pc = pcLine;
896 
897  exp.strName.buf = NULL;
898  exp.strName.len = 0;
899  exp.strTarget.buf = NULL;
900  exp.strTarget.len = 0;
901  exp.nArgCount = 0;
902  exp.uFlags = 0;
903  exp.nNumber++;
904  exp.nStartVersion = 0;
905  exp.nEndVersion = 0xFFFFFFFF;
906  exp.bVersionIncluded = 1;
907 
908  /* Skip white spaces */
909  while (*pc == ' ' || *pc == '\t') pc++;
910 
911  /* Check for line break or comment */
912  if ((*pc == '\r') || (*pc == '\n') ||
913  (*pc == ';') || (*pc == '#'))
914  {
915  continue;
916  }
917 
918  /* On EOF we are done */
919  if (*pc == 0)
920  {
921  return pexports;
922  }
923 
924  /* Now we should get either an ordinal or @ */
925  if (*pc == '@')
926  {
927  exp.nOrdinal = -1;
928  }
929  else if ((*pc >= '0') && (*pc <= '9'))
930  {
931  char* end;
932  long int number = strtol(pc, &end, 10);
933  if ((*end != ' ') && (*end != '\t'))
934  {
935  Fatal(pszSourceFileName, nLine, pcLine, end, 0, "Unexpected character(s) after ordinal");
936  }
937 
938  if ((number < 0) || (number > 0xFFFE))
939  {
940  Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Invalid value for ordinal");
941  }
942 
943  exp.nOrdinal = number;
944 
945  /* The import lib should contain the ordinal only if -ordinal was specified */
946  if (!gbImportLib)
947  exp.uFlags |= FL_ORDINAL;
948  }
949  else
950  {
951  Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Expected '@' or ordinal");
952  }
953 
954  /* Go to next token (type) */
955  if (!(pc = NextToken(pc)))
956  {
957  Fatal(pszSourceFileName, nLine, pcLine, pc, 1, "Unexpected end of line");
958  }
959 
960  //fprintf(stderr, "info: Token:'%.*s'\n", TokenLength(pc), pc);
961 
962  /* Now we should get the type */
963  if (CompareToken(pc, "stdcall"))
964  {
965  exp.nCallingConvention = CC_STDCALL;
966  }
967  else if (CompareToken(pc, "cdecl") ||
968  CompareToken(pc, "varargs"))
969  {
970  exp.nCallingConvention = CC_CDECL;
971  }
972  else if (CompareToken(pc, "fastcall"))
973  {
974  exp.nCallingConvention = CC_FASTCALL;
975  }
976  else if (CompareToken(pc, "thiscall"))
977  {
978  exp.nCallingConvention = CC_THISCALL;
979  }
980  else if (CompareToken(pc, "extern"))
981  {
982  exp.nCallingConvention = CC_EXTERN;
983  }
984  else if (CompareToken(pc, "stub"))
985  {
986  exp.nCallingConvention = CC_STUB;
987  }
988  else
989  {
990  Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Invalid calling convention");
991  }
992 
993  /* Go to next token (options or name) */
994  if (!(pc = NextToken(pc)))
995  {
996  Fatal(pszSourceFileName, nLine, pcLine, pc, 1, "Unexpected end of line");
997  }
998 
999  /* Handle options */
1000  included = 1;
1001  while (*pc == '-')
1002  {
1003  if (CompareToken(pc, "-arch="))
1004  {
1005  /* Default to not included */
1006  included = 0;
1007  pc += 5;
1008 
1009  /* Look if we are included */
1010  do
1011  {
1012  pc++;
1013  if (CompareToken(pc, pszArchString) ||
1015  {
1016  included = 1;
1017  }
1018 
1019  /* Skip to next arch or end */
1020  while (*pc > ',') pc++;
1021  } while (*pc == ',');
1022  }
1023  else if (CompareToken(pc, "-i386"))
1024  {
1025  if (giArch != ARCH_X86) included = 0;
1026  }
1027  else if (CompareToken(pc, "-version="))
1028  {
1029  const char *pcVersionStart = pc + 9;
1030 
1031  /* Default to not included */
1032  exp.bVersionIncluded = 0;
1033  pc += 8;
1034 
1035  /* Look if we are included */
1036  do
1037  {
1038  unsigned version, endversion;
1039 
1040  /* Optionally skip leading '0x' */
1041  pc++;
1042  if ((pc[0] == '0') && (pc[1] == 'x')) pc += 2;
1043 
1044  /* Now get the version number */
1045  endversion = version = strtoul(pc, (char**)&pc, 16);
1046 
1047  /* Check if it's a range */
1048  if (pc[0] == '+')
1049  {
1050  endversion = 0xFFF;
1051  pc++;
1052  }
1053  else if (pc[0] == '-')
1054  {
1055  /* Optionally skip leading '0x' */
1056  pc++;
1057  if ((pc[0] == '0') && (pc[1] == 'x')) pc += 2;
1058  endversion = strtoul(pc, (char**)&pc, 16);
1059  }
1060 
1061  /* Check for degenerate range */
1062  if (version > endversion)
1063  {
1065  nLine,
1066  pcLine,
1067  pcVersionStart,
1068  pc - pcVersionStart,
1069  "Invalid version range");
1070  }
1071 
1072  exp.nStartVersion = version;
1073  exp.nEndVersion = endversion;
1074 
1075  /* Now compare the range with our version */
1076  if ((guOsVersion >= version) &&
1077  (guOsVersion <= endversion))
1078  {
1079  exp.bVersionIncluded = 1;
1080  }
1081 
1082  /* Skip to next arch or end */
1083  while (*pc > ',') pc++;
1084 
1085  } while (*pc == ',');
1086  }
1087  else if (CompareToken(pc, "-private"))
1088  {
1089  exp.uFlags |= FL_PRIVATE;
1090  }
1091  else if (CompareToken(pc, "-noname"))
1092  {
1093  exp.uFlags |= FL_ORDINAL | FL_NONAME;
1094  }
1095  else if (CompareToken(pc, "-ordinal"))
1096  {
1097  exp.uFlags |= FL_ORDINAL;
1098  /* GCC doesn't automatically import by ordinal if an ordinal
1099  * is found in the def file. Force it. */
1100  if (gbImportLib && !gbMSComp)
1101  exp.uFlags |= FL_NONAME;
1102  }
1103  else if (CompareToken(pc, "-stub"))
1104  {
1105  exp.uFlags |= FL_STUB;
1106  }
1107  else if (CompareToken(pc, "-norelay"))
1108  {
1109  exp.uFlags |= FL_NORELAY;
1110  }
1111  else if (CompareToken(pc, "-ret64"))
1112  {
1113  exp.uFlags |= FL_RET64;
1114  }
1115  else if (CompareToken(pc, "-register"))
1116  {
1117  exp.uFlags |= FL_REGISTER;
1118  }
1119  else
1120  {
1121  fprintf(stdout,
1122  "INFO: %s line %d: Ignored option: '%.*s'\n",
1124  nLine,
1125  TokenLength(pc),
1126  pc);
1127  }
1128 
1129  /* Go to next token */
1130  pc = NextToken(pc);
1131  }
1132 
1133  //fprintf(stderr, "info: Name:'%.10s'\n", pc);
1134 
1135  /* If arch didn't match ours, skip this entry */
1136  if (!included) continue;
1137 
1138  /* Get name */
1139  exp.strName.buf = pc;
1140  exp.strName.len = TokenLength(pc);
1141  //DbgPrint("Got name: '%.*s'\n", exp.strName.len, exp.strName.buf);
1142 
1143  /* Check for autoname */
1144  if ((exp.strName.len == 1) && (exp.strName.buf[0] == '@'))
1145  {
1146  exp.uFlags |= FL_ORDINAL | FL_NONAME;
1147  }
1148 
1149  /* Handle parameters */
1150  exp.nStackBytes = 0;
1151  pc = NextToken(pc);
1152  /* Extern can't have parameters, and it's optional to provide ones for stubs. All other exports must have them */
1153  if (!pc && (exp.nCallingConvention != CC_EXTERN && exp.nCallingConvention != CC_STUB))
1154  {
1155  Fatal(pszSourceFileName, nLine, pcLine, pc, 1, "Unexpected end of line");
1156  }
1157 
1158  if (pc && (exp.nCallingConvention != CC_EXTERN))
1159  {
1160  /* Verify syntax */
1161  if (*pc++ != '(')
1162  {
1163  Fatal(pszSourceFileName, nLine, pcLine, pc - 1, 0, "Expected '('");
1164  }
1165 
1166  /* Skip whitespaces */
1167  while (*pc == ' ' || *pc == '\t') pc++;
1168 
1169  exp.nStackBytes = 0;
1170  while (*pc >= '0')
1171  {
1172  if (CompareToken(pc, "long"))
1173  {
1174  exp.nStackBytes += 4;
1175  exp.anArgs[exp.nArgCount] = ARG_LONG;
1176  }
1177  else if (CompareToken(pc, "double"))
1178  {
1179  exp.nStackBytes += 8;
1180  exp.anArgs[exp.nArgCount] = ARG_DBL;
1181  }
1182  else if (CompareToken(pc, "ptr"))
1183  {
1184  exp.nStackBytes += 4; // sizeof(void*) on x86
1185  exp.anArgs[exp.nArgCount] = ARG_PTR;
1186  }
1187  else if (CompareToken(pc, "str"))
1188  {
1189  exp.nStackBytes += 4; // sizeof(void*) on x86
1190  exp.anArgs[exp.nArgCount] = ARG_STR;
1191  }
1192  else if (CompareToken(pc, "wstr"))
1193  {
1194  exp.nStackBytes += 4; // sizeof(void*) on x86
1195  exp.anArgs[exp.nArgCount] = ARG_WSTR;
1196  }
1197  else if (CompareToken(pc, "int64"))
1198  {
1199  exp.nStackBytes += 8;
1200  exp.anArgs[exp.nArgCount] = ARG_INT64;
1201  }
1202  else if (CompareToken(pc, "int128"))
1203  {
1204  exp.nStackBytes += 16;
1205  exp.anArgs[exp.nArgCount] = ARG_INT128;
1206  }
1207  else if (CompareToken(pc, "float"))
1208  {
1209  exp.nStackBytes += 4;
1210  exp.anArgs[exp.nArgCount] = ARG_FLOAT;
1211  }
1212  else
1213  {
1214  Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Unrecognized type");
1215  }
1216 
1217  exp.nArgCount++;
1218 
1219  /* Go to next parameter */
1220  if (!(pc = NextToken(pc)))
1221  {
1222  Fatal(pszSourceFileName, nLine, pcLine, pc, 1, "Unexpected end of line");
1223  }
1224  }
1225 
1226  /* Check syntax */
1227  if (*pc++ != ')')
1228  {
1229  Fatal(pszSourceFileName, nLine, pcLine, pc - 1, 0, "Expected ')'");
1230  }
1231 
1232  /* Go to next token */
1233  pc = NextToken(pc);
1234  }
1235 
1236  /* Handle special stub cases */
1237  if (exp.nCallingConvention == CC_STUB)
1238  {
1239  /* If we got parameters, assume STDCALL */
1240  if (exp.nArgCount != 0)
1241  {
1242  exp.nCallingConvention = CC_STDCALL;
1243  exp.uFlags |= FL_STUB;
1244  }
1245 
1246  /* Check for c++ mangled name */
1247  if (exp.strName.buf[0] == '?')
1248  {
1249  //printf("Found c++ mangled name...\n");
1250  //
1251  }
1252  else
1253  {
1254  /* Check for stdcall name */
1255  const char *p = ScanToken(exp.strName.buf, '@');
1256  if (p && (p - exp.strName.buf < exp.strName.len))
1257  {
1258  int i;
1259 
1260  /* Truncate the name to before the @ */
1261  exp.strName.len = (int)(p - exp.strName.buf);
1262  if (exp.strName.len < 1)
1263  {
1264  Fatal(pszSourceFileName, nLine, pcLine, p, 1, "Unexpected @");
1265  }
1266  exp.nStackBytes = atoi(p + 1);
1267  exp.nArgCount = exp.nStackBytes / 4;
1268  exp.nCallingConvention = CC_STDCALL;
1269  exp.uFlags |= FL_STUB;
1270  for (i = 0; i < exp.nArgCount; i++)
1271  exp.anArgs[i] = ARG_LONG;
1272  }
1273  }
1274  }
1275 
1276  /* Check optional redirection */
1277  if (pc)
1278  {
1279  exp.strTarget.buf = pc;
1280  exp.strTarget.len = TokenLength(pc);
1281 
1282  /* Check syntax (end of line) */
1283  if (NextToken(pc))
1284  {
1285  Fatal(pszSourceFileName, nLine, pcLine, NextToken(pc), 0, "Excess token(s) at end of definition");
1286  }
1287 
1288  /* Don't relay-trace forwarded functions */
1289  exp.uFlags |= FL_NORELAY;
1290  }
1291  else
1292  {
1293  exp.strTarget.buf = NULL;
1294  exp.strTarget.len = 0;
1295  }
1296 
1297  /* Check for no-name without ordinal */
1298  if ((exp.uFlags & FL_ORDINAL) && (exp.nOrdinal == -1))
1299  {
1300  Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Ordinal export without ordinal");
1301  }
1302 
1303  /*
1304  * Check for special handling of OLE exports, only when MSVC
1305  * is not used, since otherwise this is handled by MS LINK.EXE.
1306  */
1307  if (!gbMSComp)
1308  {
1309  /* Check whether the current export is not PRIVATE, or has an ordinal */
1310  int bIsNotPrivate = (!gbNotPrivateNoWarn && /*gbImportLib &&*/ !(exp.uFlags & FL_PRIVATE));
1311  int bHasOrdinal = (exp.uFlags & FL_ORDINAL);
1312 
1313  /* Check whether the current export is an OLE export, in case any of these tests pass */
1314  if (bIsNotPrivate || bHasOrdinal)
1315  {
1316  for (i = 0; i < ARRAYSIZE(astrOlePrivateExports); ++i)
1317  {
1318  if (strlen(astrOlePrivateExports[i]) == exp.strName.len &&
1319  strncmp(exp.strName.buf, astrOlePrivateExports[i], exp.strName.len) == 0)
1320  {
1321  /* The current export is an OLE export: display the corresponding warning */
1322  if (bIsNotPrivate)
1323  {
1324  fprintf(stderr, "WARNING: %s line %d: Exported symbol '%.*s' should be PRIVATE\n",
1325  pszSourceFileName, nLine, exp.strName.len, exp.strName.buf);
1326  }
1327  if (bHasOrdinal)
1328  {
1329  fprintf(stderr, "WARNING: %s line %d: exported symbol '%.*s' should not be assigned an ordinal\n",
1330  pszSourceFileName, nLine, exp.strName.len, exp.strName.buf);
1331  }
1332  break;
1333  }
1334  }
1335  }
1336  }
1337 
1338  pexports[*cExports] = exp;
1339  (*cExports)++;
1340  gbDebug = 0;
1341  }
1342 
1343  return pexports;
1344 }
1345 
1346 int
1347 ApplyOrdinals(EXPORT* pexports, unsigned cExports)
1348 {
1349  unsigned short i, j;
1350  char* used;
1351 
1352  /* Allocate a table to mark used ordinals */
1353  used = malloc(65536);
1354  if (used == NULL)
1355  {
1356  fprintf(stderr, "Failed to allocate memory for ordinal use table\n");
1357  return -1;
1358  }
1359  memset(used, 0, 65536);
1360 
1361  /* Pass 1: mark the ordinals that are already used */
1362  for (i = 0; i < cExports; i++)
1363  {
1364  if (pexports[i].uFlags & FL_ORDINAL)
1365  {
1366  if (used[pexports[i].nOrdinal] != 0)
1367  {
1368  fprintf(stderr, "Found duplicate ordinal: %u\n", pexports[i].nOrdinal);
1369  return -1;
1370  }
1371  used[pexports[i].nOrdinal] = 1;
1372  }
1373  }
1374 
1375  /* Pass 2: apply available ordinals */
1376  for (i = 0, j = 1; i < cExports; i++)
1377  {
1378  if ((pexports[i].uFlags & FL_ORDINAL) == 0 && pexports[i].bVersionIncluded)
1379  {
1380  while (used[j] != 0)
1381  j++;
1382 
1383  pexports[i].nOrdinal = j;
1384  used[j] = 1;
1385  }
1386  }
1387 
1388  free(used);
1389  return 0;
1390 }
1391 
1392 void usage(void)
1393 {
1394  printf("syntax: spec2def [<options> ...] <spec file>\n"
1395  "Possible options:\n"
1396  " -h --help print this help screen\n"
1397  " -l=<file> generate an asm lib stub\n"
1398  " -d=<file> generate a def file\n"
1399  " -s=<file> generate a stub file\n"
1400  " --ms MSVC compatibility\n"
1401  " -n=<name> name of the dll\n"
1402  " --implib generate a def file for an import library\n"
1403  " --no-private-warnings suppress warnings about symbols that should be -private\n"
1404  " -a=<arch> set architecture to <arch> (i386, x86_64, arm)\n"
1405  " --with-tracing generate wine-like \"+relay\" trace trampolines (needs -s)\n");
1406 }
1407 
1408 int main(int argc, char *argv[])
1409 {
1410  size_t nFileSize;
1411  char *pszSource, *pszDefFileName = NULL, *pszStubFileName = NULL, *pszLibStubName = NULL;
1412  const char* pszVersionOption = "--version=0x";
1413  char achDllName[40];
1414  FILE *file;
1415  unsigned cExports = 0, i;
1416  EXPORT *pexports;
1417 
1418  if (argc < 2)
1419  {
1420  usage();
1421  return -1;
1422  }
1423 
1424  /* Read options */
1425  for (i = 1; i < (unsigned)argc && *argv[i] == '-'; i++)
1426  {
1427  if ((strcasecmp(argv[i], "--help") == 0) ||
1428  (strcasecmp(argv[i], "-h") == 0))
1429  {
1430  usage();
1431  return 0;
1432  }
1433  else if (argv[i][1] == 'd' && argv[i][2] == '=')
1434  {
1435  pszDefFileName = argv[i] + 3;
1436  }
1437  else if (argv[i][1] == 'l' && argv[i][2] == '=')
1438  {
1439  pszLibStubName = argv[i] + 3;
1440  }
1441  else if (argv[i][1] == 's' && argv[i][2] == '=')
1442  {
1443  pszStubFileName = argv[i] + 3;
1444  }
1445  else if (argv[i][1] == 'n' && argv[i][2] == '=')
1446  {
1447  pszDllName = argv[i] + 3;
1448  }
1449  else if (strncasecmp(argv[i], pszVersionOption, strlen(pszVersionOption)) == 0)
1450  {
1451  guOsVersion = strtoul(argv[i] + strlen(pszVersionOption), NULL, 16);
1452  }
1453  else if (strcasecmp(argv[i], "--implib") == 0)
1454  {
1455  gbImportLib = 1;
1456  }
1457  else if (strcasecmp(argv[i], "--ms") == 0)
1458  {
1459  gbMSComp = 1;
1460  }
1461  else if (strcasecmp(argv[i], "--no-private-warnings") == 0)
1462  {
1463  gbNotPrivateNoWarn = 1;
1464  }
1465  else if (strcasecmp(argv[i], "--with-tracing") == 0)
1466  {
1467  if (!pszStubFileName)
1468  {
1469  fprintf(stderr, "Error: cannot use --with-tracing without -s option.\n");
1470  return -1;
1471  }
1472  gbTracing = 1;
1473  }
1474  else if (argv[i][1] == 'a' && argv[i][2] == '=')
1475  {
1476  pszArchString = argv[i] + 3;
1477  }
1478  else
1479  {
1480  fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
1481  return -1;
1482  }
1483  }
1484 
1485  if (strcasecmp(pszArchString, "i386") == 0)
1486  {
1487  giArch = ARCH_X86;
1488  gpszUnderscore = "_";
1489  }
1490  else if (strcasecmp(pszArchString, "x86_64") == 0) giArch = ARCH_AMD64;
1491  else if (strcasecmp(pszArchString, "ia64") == 0) giArch = ARCH_IA64;
1492  else if (strcasecmp(pszArchString, "arm") == 0) giArch = ARCH_ARM;
1493  else if (strcasecmp(pszArchString, "ppc") == 0) giArch = ARCH_PPC;
1494 
1495  if ((giArch == ARCH_AMD64) || (giArch == ARCH_IA64))
1496  {
1497  pszArchString2 = "win64";
1498  }
1499  else
1500  pszArchString2 = "win32";
1501 
1502  /* Set a default dll name */
1503  if (!pszDllName)
1504  {
1505  char *p1, *p2;
1506  size_t len;
1507 
1508  p1 = strrchr(argv[i], '\\');
1509  if (!p1) p1 = strrchr(argv[i], '/');
1510  p2 = p1 = p1 ? p1 + 1 : argv[i];
1511 
1512  /* walk up to '.' */
1513  while (*p2 != '.' && *p2 != 0) p2++;
1514  len = p2 - p1;
1515  if (len >= sizeof(achDllName) - 5)
1516  {
1517  fprintf(stderr, "name too long: %s\n", p1);
1518  return -2;
1519  }
1520 
1521  strncpy(achDllName, p1, len);
1522  strncpy(achDllName + len, ".dll", sizeof(achDllName) - len);
1523  pszDllName = achDllName;
1524  }
1525 
1526  /* Open input file */
1528  file = fopen(pszSourceFileName, "r");
1529  if (!file)
1530  {
1531  fprintf(stderr, "error: could not open file %s\n", pszSourceFileName);
1532  return -3;
1533  }
1534 
1535  /* Get file size */
1536  fseek(file, 0, SEEK_END);
1537  nFileSize = ftell(file);
1538  rewind(file);
1539 
1540  /* Allocate memory buffer */
1541  pszSource = malloc(nFileSize + 1);
1542  if (!pszSource)
1543  {
1544  fclose(file);
1545  return -4;
1546  }
1547 
1548  /* Load input file into memory */
1549  nFileSize = fread(pszSource, 1, nFileSize, file);
1550  fclose(file);
1551 
1552  /* Zero terminate the source */
1553  pszSource[nFileSize] = '\0';
1554 
1555  pexports = ParseFile(pszSource, file, &cExports);
1556  if (pexports == NULL)
1557  {
1558  fprintf(stderr, "error: could not parse file!\n");
1559  return -1;
1560  }
1561 
1562  if (!gbMSComp)
1563  {
1564  if (ApplyOrdinals(pexports, cExports) < 0)
1565  {
1566  fprintf(stderr, "error: could not apply ordinals!\n");
1567  return -1;
1568  }
1569  }
1570 
1571  if (pszDefFileName)
1572  {
1573  /* Open output file */
1574  file = fopen(pszDefFileName, "w");
1575  if (!file)
1576  {
1577  fprintf(stderr, "error: could not open output file %s\n", argv[i + 1]);
1578  return -5;
1579  }
1580 
1582 
1583  for (i = 0; i < cExports; i++)
1584  {
1585  if (pexports[i].bVersionIncluded)
1586  OutputLine_def(file, &pexports[i]);
1587  }
1588 
1589  fclose(file);
1590  }
1591 
1592  if (pszStubFileName)
1593  {
1594  /* Open output file */
1595  file = fopen(pszStubFileName, "w");
1596  if (!file)
1597  {
1598  fprintf(stderr, "error: could not open output file %s\n", argv[i + 1]);
1599  return -5;
1600  }
1601 
1603 
1604  for (i = 0; i < cExports; i++)
1605  {
1606  if (pexports[i].bVersionIncluded)
1607  OutputLine_stub(file, &pexports[i]);
1608  }
1609 
1610  fclose(file);
1611  }
1612 
1613  if (pszLibStubName)
1614  {
1615  /* Open output file */
1616  file = fopen(pszLibStubName, "w");
1617  if (!file)
1618  {
1619  fprintf(stderr, "error: could not open output file %s\n", argv[i + 1]);
1620  return -5;
1621  }
1622 
1624 
1625  for (i = 0; i < cExports; i++)
1626  {
1627  if (pexports[i].bVersionIncluded)
1628  OutputLine_asmstub(file, &pexports[i]);
1629  }
1630 
1631  fprintf(file, "\n END\n");
1632  fclose(file);
1633  }
1634 
1635  free(pexports);
1636 
1637  return 0;
1638 }
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:1347
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:743
void OutputLine_def_GCC(FILE *fileDest, EXPORT *pexp)
Definition: spec2def.c:677
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:796
#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:846
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:1408
_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:1392
const char * buf
Definition: spec2def.c:16
EXPORT * ParseFile(char *pcStart, FILE *fileDest, unsigned *cExports)
Definition: spec2def.c:863
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:626
#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