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