[SPEC2DEF]
[reactos.git] / reactos / tools / spec2def / spec2def.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <ctype.h>
4 #include <string.h>
5
6 #ifdef _MSC_VER
7 #define strcasecmp _stricmp
8 #endif
9
10 typedef struct
11 {
12 char *pcName;
13 size_t nNameLength;
14 char *pcRedirection;
15 int nRedirectionLength;
16 int nCallingConvention;
17 int nOrdinal;
18 int nStackBytes;
19 int nArgCount;
20 int anArgs[30];
21 unsigned int uFlags;
22 } EXPORT;
23
24 enum _ARCH
25 {
26 ARCH_X86,
27 ARCH_AMD64,
28 ARCH_IA64,
29 ARCH_ARM,
30 ARCH_PPC
31 };
32
33 typedef int (*PFNOUTLINE)(FILE *, EXPORT *);
34 int gbKillAt = 0;
35 int gbMSComp = 0;
36 int gbImportLib = 0;
37 int no_redirections = 0;
38 int giArch = ARCH_X86;
39 char *pszArchString = "i386";
40 char *pszArchString2;
41 char *pszDllName = 0;
42 char *gpszUnderscore = "";
43
44 enum
45 {
46 FL_PRIVATE = 1,
47 FL_STUB = 2,
48 FL_NONAME = 4,
49 };
50
51 enum
52 {
53 CC_STDCALL,
54 CC_CDECL,
55 CC_FASTCALL,
56 CC_EXTERN,
57 CC_STUB,
58 };
59
60 enum
61 {
62 ARG_LONG,
63 ARG_PTR,
64 ARG_STR,
65 ARG_WSTR,
66 ARG_DBL,
67 ARG_INT64
68 };
69
70 char* astrCallingConventions[] =
71 {
72 "STDCALL",
73 "CDECL",
74 "FASTCALL",
75 "EXTERN"
76 };
77
78 static
79 int
80 IsSeparator(char chr)
81 {
82 return ((chr <= ',' && chr != '$') ||
83 (chr >= ':' && chr < '?') );
84 }
85
86 int
87 CompareToken(const char *token, const char *comparand)
88 {
89 while (*comparand)
90 {
91 if (*token != *comparand) return 0;
92 token++;
93 comparand++;
94 }
95 if (!IsSeparator(*token)) return 0;
96 return 1;
97 }
98
99 int
100 ScanToken(const char *token, char chr)
101 {
102 while (!IsSeparator(*token))
103 {
104 if (*token++ == chr) return 1;
105 }
106 return 0;
107 }
108
109 char *
110 NextLine(char *pc)
111 {
112 while (*pc != 0)
113 {
114 if (pc[0] == '\n' && pc[1] == '\r') return pc + 2;
115 else if (pc[0] == '\n') return pc + 1;
116 pc++;
117 }
118 return pc;
119 }
120
121 int
122 TokenLength(char *pc)
123 {
124 int length = 0;
125
126 while (!IsSeparator(*pc++)) length++;
127
128 return length;
129 }
130
131 char *
132 NextToken(char *pc)
133 {
134 /* Skip token */
135 while (!IsSeparator(*pc)) pc++;
136
137 /* Skip white spaces */
138 while (*pc == ' ' || *pc == '\t') pc++;
139
140 /* Check for end of line */
141 if (*pc == '\n' || *pc == '\r' || *pc == 0) return 0;
142
143 /* Check for comment */
144 if (*pc == '#' || *pc == ';') return 0;
145
146 return pc;
147 }
148
149 void
150 OutputHeader_stub(FILE *file)
151 {
152 fprintf(file, "/* This file is autogenerated, do not edit. */\n\n"
153 "#include <stubs.h>\n\n");
154 }
155
156 int
157 OutputLine_stub(FILE *file, EXPORT *pexp)
158 {
159 int i;
160
161 if (pexp->nCallingConvention != CC_STUB &&
162 (pexp->uFlags & FL_STUB) == 0) return 0;
163
164 fprintf(file, "int ");
165 if ((giArch == ARCH_X86) &&
166 pexp->nCallingConvention == CC_STDCALL)
167 {
168 fprintf(file, "__stdcall ");
169 }
170
171 fprintf(file, "%.*s(", pexp->nNameLength, pexp->pcName);
172
173 for (i = 0; i < pexp->nArgCount; i++)
174 {
175 if (i != 0) fprintf(file, ", ");
176 switch (pexp->anArgs[i])
177 {
178 case ARG_LONG: fprintf(file, "long"); break;
179 case ARG_PTR: fprintf(file, "void*"); break;
180 case ARG_STR: fprintf(file, "char*"); break;
181 case ARG_WSTR: fprintf(file, "wchar_t*"); break;
182 case ARG_DBL: case ARG_INT64 : fprintf(file, "__int64"); break;
183 }
184 fprintf(file, " a%d", i);
185 }
186 fprintf(file, ")\n{\n\tDPRINT1(\"WARNING: calling stub %.*s(",
187 pexp->nNameLength, pexp->pcName);
188
189 for (i = 0; i < pexp->nArgCount; i++)
190 {
191 if (i != 0) fprintf(file, ",");
192 switch (pexp->anArgs[i])
193 {
194 case ARG_LONG: fprintf(file, "0x%%lx"); break;
195 case ARG_PTR: fprintf(file, "0x%%p"); break;
196 case ARG_STR: fprintf(file, "'%%s'"); break;
197 case ARG_WSTR: fprintf(file, "'%%ws'"); break;
198 case ARG_DBL: fprintf(file, "%%f"); break;
199 case ARG_INT64: fprintf(file, "%%\"PRix64\""); break;
200 }
201 }
202 fprintf(file, ")\\n\"");
203
204 for (i = 0; i < pexp->nArgCount; i++)
205 {
206 fprintf(file, ", ");
207 switch (pexp->anArgs[i])
208 {
209 case ARG_LONG: fprintf(file, "(long)a%d", i); break;
210 case ARG_PTR: fprintf(file, "(void*)a%d", i); break;
211 case ARG_STR: fprintf(file, "(char*)a%d", i); break;
212 case ARG_WSTR: fprintf(file, "(wchar_t*)a%d", i); break;
213 case ARG_DBL: fprintf(file, "(double)a%d", i); break;
214 case ARG_INT64: fprintf(file, "(__int64)a%d", i); break;
215 }
216 }
217 fprintf(file, ");\n");
218
219 if (pexp->nCallingConvention == CC_STUB)
220 {
221 fprintf(file, "\t__wine_spec_unimplemented_stub(\"%s\", __FUNCTION__);\n", pszDllName);
222 }
223
224 fprintf(file, "\treturn 0;\n}\n\n");
225
226 return 1;
227 }
228
229 void
230 OutputHeader_asmstub(FILE *file, char *libname)
231 {
232 fprintf(file, "; File generated automatically, do not edit! \n\n");
233
234 if (giArch == ARCH_X86)
235 fprintf(file, ".586\n.model flat\n");
236
237 fprintf(file, ".code\n");
238 }
239
240 int
241 OutputLine_asmstub(FILE *fileDest, EXPORT *pexp)
242 {
243 /* Handle autoname */
244 if (pexp->nNameLength == 1 && pexp->pcName[0] == '@')
245 {
246 fprintf(fileDest, "PUBLIC %sordinal%d\n%sordinal%d: nop\n",
247 gpszUnderscore, pexp->nOrdinal, gpszUnderscore, pexp->nOrdinal);
248 }
249 else if (giArch != ARCH_X86)
250 {
251 fprintf(fileDest, "PUBLIC _stub_%.*s\n_stub_%.*s: nop\n",
252 pexp->nNameLength, pexp->pcName,
253 pexp->nNameLength, pexp->pcName);
254 }
255 else if (pexp->nCallingConvention == CC_STDCALL)
256 {
257 fprintf(fileDest, "PUBLIC __stub_%.*s@%d\n__stub_%.*s@%d: nop\n",
258 pexp->nNameLength, pexp->pcName, pexp->nStackBytes,
259 pexp->nNameLength, pexp->pcName, pexp->nStackBytes);
260 }
261 else if (pexp->nCallingConvention == CC_FASTCALL)
262 {
263 fprintf(fileDest, "PUBLIC @_stub_%.*s@%d\n@_stub_%.*s@%d: nop\n",
264 pexp->nNameLength, pexp->pcName, pexp->nStackBytes,
265 pexp->nNameLength, pexp->pcName, pexp->nStackBytes);
266 }
267 else if (pexp->nCallingConvention == CC_CDECL ||
268 pexp->nCallingConvention == CC_STUB)
269 {
270 fprintf(fileDest, "PUBLIC __stub_%.*s\n__stub_%.*s: nop\n",
271 pexp->nNameLength, pexp->pcName,
272 pexp->nNameLength, pexp->pcName);
273 }
274 else if (pexp->nCallingConvention == CC_EXTERN)
275 {
276 fprintf(fileDest, "PUBLIC __stub_%.*s\n__stub_%.*s:\n",
277 pexp->nNameLength, pexp->pcName,
278 pexp->nNameLength, pexp->pcName);
279 }
280
281 return 1;
282 }
283
284 void
285 OutputHeader_def(FILE *file, char *libname)
286 {
287 fprintf(file,
288 "; File generated automatically, do not edit!\n\n"
289 "LIBRARY %s\n\n"
290 "EXPORTS\n",
291 libname);
292 }
293
294 void
295 PrintName(FILE *fileDest, EXPORT *pexp, char *pszPrefix, int fRedir, int fDeco)
296 {
297 char *pcName = fRedir ? pexp->pcRedirection : pexp->pcName;
298 size_t nNameLength = fRedir ? pexp->nRedirectionLength : pexp->nNameLength;
299
300 /* Handle autoname */
301 if (nNameLength == 1 && pcName[0] == '@')
302 {
303 fprintf(fileDest, "ordinal%d", pexp->nOrdinal);
304 }
305 else
306 {
307 if (fDeco && pexp->nCallingConvention == CC_FASTCALL)
308 fprintf(fileDest, "@");
309 fprintf(fileDest, "%s%.*s", pszPrefix, nNameLength, pcName);
310 if ((pexp->nCallingConvention == CC_STDCALL ||
311 pexp->nCallingConvention == CC_FASTCALL) && fDeco)
312 {
313 fprintf(fileDest, "@%d", pexp->nStackBytes);
314 }
315 }
316 }
317
318 int
319 OutputLine_def(FILE *fileDest, EXPORT *pexp)
320 {
321 fprintf(fileDest, " ");
322
323 PrintName(fileDest, pexp, "", 0, (giArch == ARCH_X86) && !gbKillAt);
324
325 if (gbImportLib)
326 {
327 fprintf(fileDest, "=");
328 PrintName(fileDest, pexp, "_stub_", 0, 0);
329 }
330 else if (pexp->pcRedirection)
331 {
332 int fDeco = ((giArch == ARCH_X86) && !ScanToken(pexp->pcRedirection, '.'));
333
334 fprintf(fileDest, "=");
335 PrintName(fileDest, pexp, "", 1, fDeco && !gbMSComp);
336 }
337 else if ((giArch == ARCH_X86) && gbKillAt && !gbMSComp &&
338 (pexp->nCallingConvention == CC_STDCALL ||
339 pexp->nCallingConvention == CC_FASTCALL))
340 {
341 fprintf(fileDest, "=");
342 PrintName(fileDest, pexp, "", 0, 1);
343 }
344
345 if (pexp->nOrdinal != -1)
346 {
347 fprintf(fileDest, " @%d", pexp->nOrdinal);
348 }
349
350 if (pexp->nCallingConvention == CC_EXTERN)
351 {
352 fprintf(fileDest, " DATA");
353 }
354
355 if (pexp->uFlags & FL_PRIVATE)
356 {
357 fprintf(fileDest, " PRIVATE");
358 }
359
360 if (pexp->uFlags & FL_NONAME)
361 {
362 fprintf(fileDest, " NONAME");
363 }
364
365 fprintf(fileDest, "\n");
366
367 return 1;
368 }
369
370 int
371 ParseFile(char* pcStart, FILE *fileDest, PFNOUTLINE OutputLine)
372 {
373 char *pc, *pcLine;
374 int nLine;
375 EXPORT exp;
376 int included;
377
378 //fprintf(stderr, "info: line %d, pcStart:'%.30s'\n", nLine, pcStart);
379
380 /* Loop all lines */
381 nLine = 1;
382 for (pcLine = pcStart; *pcLine; pcLine = NextLine(pcLine), nLine++)
383 {
384 pc = pcLine;
385
386 exp.nArgCount = 0;
387 exp.uFlags = 0;
388
389 //fprintf(stderr, "info: line %d, token:'%d, %.20s'\n",
390 // nLine, TokenLength(pcLine), pcLine);
391
392 /* Skip white spaces */
393 while (*pc == ' ' || *pc == '\t') pc++;
394
395 /* Skip empty lines, stop at EOF */
396 if (*pc == ';' || *pc <= '#') continue;
397 if (*pc == 0) return 0;
398
399 //fprintf(stderr, "info: line %d, token:'%.*s'\n",
400 // nLine, TokenLength(pc), pc);
401
402 /* Now we should get either an ordinal or @ */
403 if (*pc == '@') exp.nOrdinal = -1;
404 else exp.nOrdinal = atol(pc);
405
406 /* Go to next token (type) */
407 if (!(pc = NextToken(pc)))
408 {
409 fprintf(stderr, "error: line %d, unexpected end of line\n", nLine);
410 return -10;
411 }
412
413 //fprintf(stderr, "info: Token:'%.10s'\n", pc);
414
415 /* Now we should get the type */
416 if (CompareToken(pc, "stdcall"))
417 {
418 exp.nCallingConvention = CC_STDCALL;
419 }
420 else if (CompareToken(pc, "cdecl") ||
421 CompareToken(pc, "varargs"))
422 {
423 exp.nCallingConvention = CC_CDECL;
424 }
425 else if (CompareToken(pc, "fastcall"))
426 {
427 exp.nCallingConvention = CC_FASTCALL;
428 }
429 else if (CompareToken(pc, "extern"))
430 {
431 exp.nCallingConvention = CC_EXTERN;
432 }
433 else if (CompareToken(pc, "stub"))
434 {
435 exp.nCallingConvention = CC_STUB;
436 }
437 else
438 {
439 fprintf(stderr, "error: line %d, expected type, got '%.*s' %d\n",
440 nLine, TokenLength(pc), pc, *pc);
441 return -11;
442 }
443
444 //fprintf(stderr, "info: nCallingConvention: %d\n", exp.nCallingConvention);
445
446 /* Go to next token (options or name) */
447 if (!(pc = NextToken(pc)))
448 {
449 fprintf(stderr, "fail2\n");
450 return -12;
451 }
452
453 /* Handle options */
454 included = 1;
455 while (*pc == '-')
456 {
457 if (CompareToken(pc, "-arch"))
458 {
459 /* Default to not included */
460 included = 0;
461 pc += 5;
462
463 /* Look if we are included */
464 while (*pc == '=' || *pc == ',')
465 {
466 pc++;
467 if (CompareToken(pc, pszArchString) ||
468 CompareToken(pc, pszArchString2))
469 {
470 included = 1;
471 }
472
473 /* Skip to next arch or end */
474 while (*pc > ',') pc++;
475 }
476 }
477 else if (CompareToken(pc, "-i386"))
478 {
479 if (giArch != ARCH_X86) included = 0;
480 }
481 else if (CompareToken(pc, "-private"))
482 {
483 exp.uFlags |= FL_PRIVATE;
484 }
485 else if (CompareToken(pc, "-noname") ||
486 CompareToken(pc, "-ordinal"))
487 {
488 exp.uFlags |= FL_NONAME;
489 }
490 else if (CompareToken(pc, "-stub"))
491 {
492 exp.uFlags |= FL_STUB;
493 }
494 else if (CompareToken(pc, "-norelay") ||
495 CompareToken(pc, "-register") ||
496 CompareToken(pc, "-ret64"))
497 {
498 /* silently ignore these */
499 }
500 else
501 {
502 fprintf(stderr, "info: ignored option: '%.*s'\n",
503 TokenLength(pc), pc);
504 }
505
506 /* Go to next token */
507 pc = NextToken(pc);
508 }
509
510 //fprintf(stderr, "info: Name:'%.10s'\n", pc);
511
512 /* If arch didn't match ours, skip this entry */
513 if (!included) continue;
514
515 /* Get name */
516 exp.pcName = pc;
517 exp.nNameLength = TokenLength(pc);
518
519 /* Handle parameters */
520 exp.nStackBytes = 0;
521 if (exp.nCallingConvention != CC_EXTERN &&
522 exp.nCallingConvention != CC_STUB)
523 {
524 //fprintf(stderr, "info: options:'%.10s'\n", pc);
525 /* Go to next token */
526 if (!(pc = NextToken(pc)))
527 {
528 fprintf(stderr, "fail4\n");
529 return -13;
530 }
531
532 /* Verify syntax */
533 if (*pc++ != '(')
534 {
535 fprintf(stderr, "error: line %d, expected '('\n", nLine);
536 return -14;
537 }
538
539 /* Skip whitespaces */
540 while (*pc == ' ' || *pc == '\t') pc++;
541
542 exp.nStackBytes = 0;
543 while (*pc >= '0')
544 {
545 if (CompareToken(pc, "long"))
546 {
547 exp.nStackBytes += 4;
548 exp.anArgs[exp.nArgCount] = ARG_LONG;
549 }
550 else if (CompareToken(pc, "double"))
551 {
552 exp.nStackBytes += 8;
553 exp.anArgs[exp.nArgCount] = ARG_DBL;
554 }
555 else if (CompareToken(pc, "ptr") ||
556 CompareToken(pc, "str") ||
557 CompareToken(pc, "wstr"))
558 {
559 exp.nStackBytes += 4; // sizeof(void*) on x86
560 exp.anArgs[exp.nArgCount] = ARG_PTR; // FIXME: handle strings
561 }
562 else if (CompareToken(pc, "int64"))
563 {
564 exp.nStackBytes += 8;
565 exp.anArgs[exp.nArgCount] = ARG_INT64;
566 }
567 else
568 fprintf(stderr, "error: line %d, expected type, got: %.10s\n", nLine, pc);
569
570 exp.nArgCount++;
571
572 /* Go to next parameter */
573 if (!(pc = NextToken(pc)))
574 {
575 fprintf(stderr, "fail5\n");
576 return -15;
577 }
578 }
579
580 /* Check syntax */
581 if (*pc++ != ')')
582 {
583 fprintf(stderr, "error: line %d, expected ')'\n", nLine);
584 return -16;
585 }
586 }
587
588 /* Handle special stub cases */
589 if (exp.nCallingConvention == CC_STUB)
590 {
591 /* Check for c++ mangled name */
592 if (pc[0] == '?')
593 {
594 printf("Found c++ mangled name...\n");
595 //
596 }
597 else
598 {
599 /* Check for stdcall name */
600 char *p = strchr(pc, '@');
601 if (p && ((size_t)(p - pc) < exp.nNameLength))
602 {
603 int i;
604 exp.nNameLength = p - pc;
605 if (exp.nNameLength < 1)
606 {
607 fprintf(stderr, "error, @ in line %d\n", nLine);
608 return -1;
609 }
610 exp.nStackBytes = atoi(p + 1);
611 exp.nArgCount = exp.nStackBytes / 4;
612 exp.nCallingConvention = CC_STDCALL;
613 exp.uFlags |= FL_STUB;
614 for (i = 0; i < exp.nArgCount; i++)
615 exp.anArgs[i] = ARG_LONG;
616 }
617 }
618 }
619
620 /* Get optional redirection */
621 if ((pc = NextToken(pc)))
622 {
623 exp.pcRedirection = pc;
624 exp.nRedirectionLength = TokenLength(pc);
625
626 /* Check syntax (end of line) */
627 if (NextToken(pc))
628 {
629 fprintf(stderr, "error: line %d, additional tokens after ')'\n", nLine);
630 return -17;
631 }
632 }
633 else
634 {
635 exp.pcRedirection = 0;
636 exp.nRedirectionLength = 0;
637 }
638
639 OutputLine(fileDest, &exp);
640 }
641
642 return 0;
643 }
644
645
646 void usage(void)
647 {
648 printf("syntax: spec2pdef [<options> ...] <spec file>\n"
649 "Possible options:\n"
650 " -h --help prints this screen\n"
651 " -l=<file> generates an asm lib stub\n"
652 " -d=<file> generates a def file\n"
653 " -s=<file> generates a stub file\n"
654 " --ms msvc compatibility\n"
655 " -n=<name> name of the dll\n"
656 " --kill-at removes @xx decorations from exports\n"
657 " -r removes redirections from def file\n"
658 " -a=<arch> Set architecture to <arch>. (i386, x86_64, arm)\n");
659 }
660
661 int main(int argc, char *argv[])
662 {
663 size_t nFileSize;
664 char *pszSource, *pszDefFileName = 0, *pszStubFileName = 0, *pszLibStubName = 0;
665 char achDllName[40];
666 FILE *file;
667 int result, i;
668
669 if (argc < 2)
670 {
671 usage();
672 return -1;
673 }
674
675 /* Read options */
676 for (i = 1; i < argc && *argv[i] == '-'; i++)
677 {
678 if ((strcasecmp(argv[i], "--help") == 0) ||
679 (strcasecmp(argv[i], "-h") == 0))
680 {
681 usage();
682 return 0;
683 }
684 else if (argv[i][1] == 'd' && argv[i][2] == '=')
685 {
686 pszDefFileName = argv[i] + 3;
687 }
688 else if (argv[i][1] == 'l' && argv[i][2] == '=')
689 {
690 pszLibStubName = argv[i] + 3;
691 }
692 else if (argv[i][1] == 's' && argv[i][2] == '=')
693 {
694 pszStubFileName = argv[i] + 3;
695 }
696 else if (argv[i][1] == 'n' && argv[i][2] == '=')
697 {
698 pszDllName = argv[i] + 3;
699 }
700 else if ((strcasecmp(argv[i], "--implib") == 0))
701 {
702 no_redirections = 1;
703 gbImportLib = 1;
704 }
705 else if ((strcasecmp(argv[i], "--kill-at") == 0))
706 {
707 gbKillAt = 1;
708 }
709 else if ((strcasecmp(argv[i], "--ms") == 0))
710 {
711 gbMSComp = 1;
712 }
713 else if ((strcasecmp(argv[i], "-r") == 0))
714 {
715 no_redirections = 1;
716 }
717 else if (argv[i][1] == 'a' && argv[i][2] == '=')
718 {
719 pszArchString = argv[i] + 3;
720 }
721 else
722 {
723 fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
724 return -1;
725 }
726 }
727
728 if (strcasecmp(pszArchString, "i386") == 0)
729 {
730 giArch = ARCH_X86;
731 gpszUnderscore = "_";
732 }
733 else if (strcasecmp(pszArchString, "x86_64") == 0) giArch = ARCH_AMD64;
734 else if (strcasecmp(pszArchString, "ia64") == 0) giArch = ARCH_IA64;
735 else if (strcasecmp(pszArchString, "arm") == 0) giArch = ARCH_ARM;
736 else if (strcasecmp(pszArchString, "ppc") == 0) giArch = ARCH_PPC;
737
738 if ((giArch == ARCH_AMD64) || (giArch == ARCH_IA64))
739 {
740 pszArchString2 = "win64";
741 }
742 else
743 pszArchString2 = "win32";
744
745 /* Set a default dll name */
746 if (!pszDllName)
747 {
748 char *p1, *p2;
749 size_t len;
750
751 p1 = strrchr(argv[i], '\\');
752 if (!p1) p1 = strrchr(argv[i], '/');
753 p2 = p1 = p1 ? p1 + 1 : argv[i];
754
755 /* walk up to '.' */
756 while (*p2 != '.' && *p2 != 0) p2++;
757 len = p2 - p1;
758 if (len >= sizeof(achDllName) - 5)
759 {
760 fprintf(stderr, "name too long: %s\n", p1);
761 return -2;
762 }
763
764 strncpy(achDllName, p1, len);
765 strncpy(achDllName + len, ".dll", sizeof(achDllName) - len);
766 pszDllName = achDllName;
767 }
768
769 /* Open input file argv[1] */
770 file = fopen(argv[i], "r");
771 if (!file)
772 {
773 fprintf(stderr, "error: could not open file %s ", argv[i]);
774 return -3;
775 }
776
777 /* Get file size */
778 fseek(file, 0, SEEK_END);
779 nFileSize = ftell(file);
780 rewind(file);
781
782 /* Allocate memory buffer */
783 pszSource = malloc(nFileSize + 1);
784 if (!pszSource) return -4;
785
786 /* Load input file into memory */
787 nFileSize = fread(pszSource, 1, nFileSize, file);
788 fclose(file);
789
790 /* Zero terminate the source */
791 pszSource[nFileSize] = '\0';
792
793 if (pszDefFileName)
794 {
795 /* Open output file */
796 file = fopen(pszDefFileName, "w");
797 if (!file)
798 {
799 fprintf(stderr, "error: could not open output file %s ", argv[i + 1]);
800 return -5;
801 }
802
803 OutputHeader_def(file, pszDllName);
804 result = ParseFile(pszSource, file, OutputLine_def);
805 fclose(file);
806 }
807
808 if (pszStubFileName)
809 {
810 /* Open output file */
811 file = fopen(pszStubFileName, "w");
812 if (!file)
813 {
814 fprintf(stderr, "error: could not open output file %s ", argv[i + 1]);
815 return -5;
816 }
817
818 OutputHeader_stub(file);
819 result = ParseFile(pszSource, file, OutputLine_stub);
820 fclose(file);
821 }
822
823 if (pszLibStubName)
824 {
825 /* Open output file */
826 file = fopen(pszLibStubName, "w");
827 if (!file)
828 {
829 fprintf(stderr, "error: could not open output file %s ", argv[i + 1]);
830 return -5;
831 }
832
833 OutputHeader_asmstub(file, pszDllName);
834 result = ParseFile(pszSource, file, OutputLine_asmstub);
835 fprintf(file, "\nEND\n");
836 fclose(file);
837 }
838
839
840 return result;
841 }