2 * Code generation functions
4 * Copyright 2000 Jon Griffiths
9 static FILE *specfile
= NULL
;
10 static FILE *hfile
= NULL
;
11 static FILE *cfile
= NULL
;
13 static void output_spec_postamble (void);
14 static void output_header_postamble (void);
15 static void output_c_postamble (void);
16 static void output_prototype (FILE *file
, const parsed_symbol
*sym
);
17 static void output_c_banner (const parsed_symbol
*sym
);
18 static const char *get_format_str (int type
);
19 static const char *get_in_or_out (const parsed_symbol
*sym
, size_t arg
);
22 /*******************************************************************
23 * output_spec_preamble
25 * Write the first part of the .spec file
27 void output_spec_preamble (void)
29 specfile
= open_file (OUTPUT_DLL_NAME
, ".spec", "w");
31 atexit (output_spec_postamble
);
34 puts ("Creating .spec preamble");
37 "# Generated from %s.dll by specmaker\nname %s\n"
38 "type win32\ninit %s_Init\n\nimport kernel32.dll\n"
39 "import ntdll.dll\n", globals
.input_name
, OUTPUT_DLL_NAME
,
42 if (globals
.forward_dll
)
43 fprintf (specfile
,"#import %s.dll\n", globals
.forward_dll
);
45 fprintf (specfile
, "\n\ndebug_channels (%s)\n\n", OUTPUT_DLL_NAME
);
49 /*******************************************************************
52 * Write a symbol to the .spec file
54 void output_spec_symbol (const parsed_symbol
*sym
)
57 assert (sym
&& sym
->symbol
);
59 if (!globals
.do_code
|| !sym
->function_name
)
61 if (globals
.forward_dll
)
62 fprintf (specfile
, "@ forward %s %s.%s\n", sym
->symbol
,
63 globals
.forward_dll
, sym
->symbol
);
66 if (!symbol_is_valid_c (sym
))
67 fputc ('#', specfile
);
68 fprintf (specfile
, "@ stub %s\n", sym
->symbol
);
75 fprintf (specfile
, "@ %s %s(", sym
->varargs
? "varargs" :
76 symbol_is_cdecl (sym
) ? "cdecl" : "stdcall", sym
->symbol
);
78 for (i
= 0; i
< sym
->argc
; i
++)
79 fprintf (specfile
, " %s", symbol_get_spec_type(sym
, i
));
82 fputc (' ', specfile
);
83 fprintf (specfile
, ") %s_%s\n", OUTPUT_UC_DLL_NAME
, sym
->function_name
);
88 /*******************************************************************
89 * output_spec_postamble
91 * Write the last part of the .spec file
93 static void output_spec_postamble (void)
101 /*******************************************************************
102 * output_header_preamble
104 * Write the first part of the .h file
106 void output_header_preamble (void)
108 hfile
= open_file (OUTPUT_DLL_NAME
, "_dll.h", "w");
110 atexit (output_header_postamble
);
113 "/*\n * %s.dll\n *\n * Generated from %s.dll by specmaker.\n *\n"
114 " * DO NOT SEND GENERATED DLLS FOR INCLUSION INTO WINE !\n * \n */"
115 "\n#ifndef __WINE_%s_DLL_H\n#define __WINE_%s_DLL_H\n\n#include "
116 "\"config.h\"\n#include \"windef.h\"\n#include \"debugtools.h\"\n"
117 "#include \"winbase.h\"\n#include \"winnt.h\"\n\n\n",
118 OUTPUT_DLL_NAME
, OUTPUT_DLL_NAME
, OUTPUT_UC_DLL_NAME
,
123 /*******************************************************************
124 * output_header_symbol
126 * Write a symbol to the .h file
128 void output_header_symbol (const parsed_symbol
*sym
)
131 assert (sym
&& sym
->symbol
);
133 if (!globals
.do_code
)
136 if (!sym
->function_name
)
137 fprintf (hfile
, "/* %s %s_%s(); */\n", CALLING_CONVENTION
,
138 OUTPUT_UC_DLL_NAME
, sym
->symbol
);
141 output_prototype (hfile
, sym
);
142 fputs (";\n", hfile
);
147 /*******************************************************************
148 * output_header_postamble
150 * Write the last part of the .h file
152 static void output_header_postamble (void)
156 fprintf (hfile
, "\n\n\n#endif\t/* __WINE_%s_DLL_H */\n",
164 /*******************************************************************
167 * Write the first part of the .c file
169 void output_c_preamble (void)
171 cfile
= open_file (OUTPUT_DLL_NAME
, "_main.c", "w");
173 atexit (output_c_postamble
);
176 "/*\n * %s.dll\n *\n * Generated from %s.dll by specmaker.\n *\n"
177 " * DO NOT SUBMIT GENERATED DLLS FOR INCLUSION INTO WINE!\n * \n */"
178 "\n\n#include \"%s_dll.h\"\n\nDEFAULT_DEBUG_CHANNEL(%s);\n\n",
179 OUTPUT_DLL_NAME
, globals
.input_name
, OUTPUT_DLL_NAME
,
182 if (globals
.forward_dll
)
185 puts ("Creating a forwarding DLL");
187 fputs ("\nHMODULE hDLL=0;\t/* DLL to call */\n\n\n", cfile
);
191 "BOOL WINAPI %s_Init(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID "
192 "lpvReserved)\n{\n\tTRACE(\"(0x%%08x, %%ld, %%p)\\n\",hinstDLL,"
193 "fdwReason,lpvReserved);\n\n\t"
194 "if (fdwReason == DLL_PROCESS_ATTACH)\n\t{\n\t\t",
197 if (globals
.forward_dll
)
200 "hDLL = LoadLibraryA( \"%s\" );\n\t\t"
201 "TRACE(\":Forwarding DLL (%s) loaded (%%ld)\\n\",(LONG)hDLL);",
202 globals
.forward_dll
, globals
.forward_dll
);
205 fputs ("/* FIXME: Initialisation */", cfile
);
207 fputs ("\n\t}\n\telse if (fdwReason == DLL_PROCESS_DETACH)\n\t{\n\t\t",
210 if (globals
.forward_dll
)
213 "FreeLibrary( hDLL );\n\t\tTRACE(\":Forwarding DLL (%s)"
214 " freed\\n\");", globals
.forward_dll
);
217 fputs ("/* FIXME: Cleanup */", cfile
);
219 fputs ("\n\t}\n\n\treturn TRUE;\n}\n\n\n", cfile
);
223 /*******************************************************************
226 * Write a symbol to the .c file
228 void output_c_symbol (const parsed_symbol
*sym
)
234 assert (sym
&& sym
->symbol
);
236 if (!globals
.do_code
)
239 output_c_banner(sym
);
241 if (!sym
->function_name
)
244 fprintf (cfile
, "#if 0\n%s %s_%s()\n{\n\t%s in .spec */\n}\n#endif\n\n\n",
245 CALLING_CONVENTION
, OUTPUT_UC_DLL_NAME
, sym
->symbol
,
246 globals
.forward_dll
? "/* @forward" : "/* @stub");
250 is_void
= !strcmp (sym
->return_text
, "void");
252 output_prototype (cfile
, sym
);
253 fputs ("\n{\n", cfile
);
255 if (!globals
.do_trace
)
257 fputs ("\tFIXME(\":stub\\n\");\n", cfile
);
259 fprintf (cfile
, "\treturn (%s) 0;\n", sym
->return_text
);
260 fputs ("}\n\n\n", cfile
);
264 /* Tracing, maybe forwarding as well */
265 if (globals
.forward_dll
)
267 /* Write variables for calling */
268 fprintf (cfile
, "\t%s (%s *pFunc)(", sym
->return_text
,
269 sym
->calling_convention
);
271 for (i
= 0; i
< sym
->argc
; i
++)
272 fprintf (cfile
, "%s%s", i
? ", " : "", sym
->arg_text
[i
]);
274 fprintf (cfile
, "%s)=(void*)GetProcAddress(hDLL,\"%s\");\n%s",
275 sym
->varargs
? ",..." : sym
->argc
? "" : "void", sym
->symbol
,
276 sym
->varargs
? "\tva_list valist;\n" : "");
279 fprintf (cfile
, "\t%s retVal;\n", sym
->return_text
);
282 /* TRACE input arguments */
283 fprintf (cfile
, "\tTRACE(\"(%s", !sym
->argc
? "void" : "");
285 for (i
= 0; i
< sym
->argc
; i
++)
286 fprintf (cfile
, "%s(%s)%s", i
? "," : "", sym
->arg_text
[i
],
287 get_format_str (sym
->arg_type
[i
]));
289 fprintf (cfile
, "%s): %s\\n\"", sym
->varargs
? ",..." : "",
290 globals
.forward_dll
? "forward" : "stub");
292 for (i
= 0; i
< sym
->argc
; i
++)
293 if (sym
->arg_type
[i
] != ARG_STRUCT
)
294 fprintf(cfile
, ",%s%s%s%s", sym
->arg_type
[i
] == ARG_LONG
? "(LONG)" : "",
295 sym
->arg_type
[i
] == ARG_WIDE_STRING
? "debugstr_w(" : "",
297 sym
->arg_type
[i
] == ARG_WIDE_STRING
? ")" : "");
299 fputs (");\n", cfile
);
301 if (!globals
.forward_dll
)
304 fprintf (cfile
, "\treturn (%s) 0;\n", sym
->return_text
);
305 fputs ("}\n\n\n", cfile
);
311 fprintf (cfile
, "\tva_start(valist,%s);\n", sym
->arg_name
[sym
->argc
-1]);
313 fprintf (cfile
, "\t%spFunc(", !is_void
? "retVal = " : "");
315 for (i
= 0; i
< sym
->argc
; i
++)
316 fprintf (cfile
, "%s%s", i
? "," : "", sym
->arg_name
[i
]);
318 fputs (sym
->varargs
? ",valist);\n\tva_end(valist);" : ");", cfile
);
320 /* TRACE return value */
321 fprintf (cfile
, "\n\tTRACE(\"Returned (%s)\\n\"",
322 get_format_str (sym
->return_type
));
326 if (sym
->return_type
== ARG_WIDE_STRING
)
327 fputs (",debugstr_w(retVal)", cfile
);
329 fprintf (cfile
, ",%s%s", sym
->return_type
== ARG_LONG
? "(LONG)" : "",
330 sym
->return_type
== ARG_STRUCT
? "" : "retVal");
331 fputs (");\n\treturn retVal;\n", cfile
);
334 fputs (");\n", cfile
);
336 fputs ("}\n\n\n", cfile
);
340 /*******************************************************************
343 * Write the last part of the .c file
345 static void output_c_postamble (void)
353 /*******************************************************************
356 * Write a Wine compatable makefile.in
358 void output_makefile (void)
360 FILE *makefile
= open_file ("Makefile", ".in", "w");
363 puts ("Creating makefile");
366 "# Generated from %s.dll by specmaker.\nTOPSRCDIR = @top_srcdir@\n"
367 "TOPOBJDIR = ../..\nSRCDIR = @srcdir@\nVPATH = @srcdir@\n"
368 "MODULE = %s\nEXTRALIBS = $(LIBUNICODE)\n\n"
369 "LDDLLFLAGS = @LDDLLFLAGS@\nSYMBOLFILE = $(MODULE).tmp.o\n\n"
370 "C_SRCS = \\\n\t%s_main.c\n\n@MAKE_DLL_RULES@\n\n### Dependencies:",
371 globals
.input_name
, OUTPUT_DLL_NAME
, OUTPUT_DLL_NAME
);
377 /*******************************************************************
378 * output_install_script
380 * Write a script to insert the DLL into Wine
382 * Rather than using diff/patch, several sed calls are generated
383 * so the script can be re-run at any time without breaking.
385 void output_install_script (void)
388 FILE *install_file
= open_file (OUTPUT_DLL_NAME
, "_install", "w");
391 puts ("Creating install script");
393 fprintf (install_file
,
394 "#!/bin/bash\n# Generated from %s.dll by specmaker.\n\n"
395 "if [ $# -ne 1 ] || [ ! -d $1 ] || [ ! -f"
396 " $1/AUTHORS ]; then\n\t[ $# -eq 1 ] && echo \"Invalid path\"\n"
397 "\techo \"Usage: $0 wine-base-dir\"\n\texit 1\nfi\n\n"
398 "if [ -d $1/dlls/%s ]; then\n\techo \"DLL is already present\"\n"
399 "\texit 1\nfi\n\necho Adding DLL %s to Wine build tree...\n"
400 "echo\n\nmkdir $1/dlls/%s\ncp %s.spec $1/dlls/%s\n"
401 "cp %s_main.c $1/dlls/%s\ncp %s_dll.h $1/dlls/%s\n"
402 "cp Makefile.in $1/dlls/%s\necho Copied DLL files\n\n"
403 "cd $1\n\nsed '/dlls\\/"
404 "x11drv\\/Makefile/{G;s/$/dlls\\/%s\\/Makefile/;}' configure.in"
405 " >t.tmp\nmv -f t.tmp configure.in\necho Patched configure.in\n\n"
406 "sed '/ws2_32/{G;s/$/\\^%s \\\\/;}' Make.rules.in | tr ^ \\\\t"
407 " >t.tmp\nmv -f t.tmp Make.rules.in\necho Patched Make.rules.in"
408 "\n\nsed '/DLLFILES =/{G;s/$/\\^%s\\/lib%s.so \\\\/;}'"
409 " dlls/Makefile.in| tr ^ \\\\t >t.tmp\n"
410 "sed '/SUBDIRS =/{G;s/$/\\^%s \\\\/;}' t.tmp | tr ^ \\\\t >t.tmp2"
411 "\nsed '/Map library name /{G;s/$/^\\$(RM) \\$\\@ \\&\\& \\$\\"
412 "(LN_S\\) %s\\/lib%s.\\@LIBEXT\\@ \\$\\@/;}' t.tmp2 | tr ^ \\\\t"
413 " > t.tmp\nsed '/Map library name /{G;s/$/lib%s.\\@LIBEXT\\@: "
414 "%s\\/lib%s.\\@LIBEXT\\@/;}' t.tmp > t.tmp2\nsed '/dll "
415 "dependencies /{G;s/$/%s\\/lib%s.\\@LIBEXT\\@\\: libkernel32."
416 "\\@LIBEXT\\@ libntdll.\\@LIBEXT\\@/;}' t.tmp2 > t.tmp\n"
417 "mv -f t.tmp dlls/Makefile.in\nrm -f t.tmp2\necho Patched dlls/"
418 "Makefile.in\n\necho\necho ...done.\necho Run \\'autoconf\\', "
419 "\\'./configure\\' then \\'make\\' to rebuild Wine\n\n",
420 OUTPUT_DLL_NAME
, OUTPUT_DLL_NAME
, OUTPUT_DLL_NAME
, OUTPUT_DLL_NAME
,
421 OUTPUT_DLL_NAME
, OUTPUT_DLL_NAME
, OUTPUT_DLL_NAME
, OUTPUT_DLL_NAME
,
422 OUTPUT_DLL_NAME
, OUTPUT_DLL_NAME
, OUTPUT_DLL_NAME
, OUTPUT_DLL_NAME
,
423 OUTPUT_DLL_NAME
, OUTPUT_DLL_NAME
, OUTPUT_DLL_NAME
, OUTPUT_DLL_NAME
,
424 OUTPUT_DLL_NAME
, OUTPUT_DLL_NAME
, OUTPUT_DLL_NAME
, OUTPUT_DLL_NAME
,
425 OUTPUT_DLL_NAME
, OUTPUT_DLL_NAME
, OUTPUT_DLL_NAME
);
427 fclose (install_file
);
428 snprintf (cmd
, sizeof (cmd
), "chmod a+x %s_install", OUTPUT_DLL_NAME
);
433 /*******************************************************************
436 * Write a C prototype for a parsed symbol
438 static void output_prototype (FILE *file
, const parsed_symbol
*sym
)
442 fprintf (file
, "%s %s %s_%s(", sym
->return_text
, sym
->calling_convention
,
443 OUTPUT_UC_DLL_NAME
, sym
->function_name
);
446 fputs ("void", file
);
448 for (i
= 0; i
< sym
->argc
; i
++)
449 fprintf (file
, "%s%s %s", i
? ", " : "", sym
->arg_text
[i
],
452 fputs (", ...", file
);
457 /*******************************************************************
460 * Write a function banner to the .c file
462 void output_c_banner (const parsed_symbol
*sym
)
466 fprintf (cfile
, "/*********************************************************"
467 "*********\n *\t\t%s (%s.@)\n *\n", sym
->symbol
,
470 if (globals
.do_documentation
&& sym
->function_name
)
472 fputs (" *\n * PARAMS\n *\n", cfile
);
475 fputs (" * None.\n *\n", cfile
);
478 for (i
= 0; i
< sym
->argc
; i
++)
479 fprintf (cfile
, " * %s [%s]%s\n", sym
->arg_name
[i
],
480 get_in_or_out(sym
, i
),
481 strcmp (sym
->arg_name
[i
], "_this") ? "" :
482 " Pointer to the class object");
485 fputs (" * ...[I]\n", cfile
);
486 fputs (" *\n", cfile
);
489 fputs (" * RETURNS\n *\n", cfile
);
491 if (sym
->return_text
&& !strcmp (sym
->return_text
, "void"))
492 fputs (" * Nothing.\n", cfile
);
494 fprintf (cfile
, " * %s\n", sym
->return_text
);
496 fputs (" *\n */\n", cfile
);
500 /*******************************************************************
503 * Get a string containing the correct format string for a type
505 static const char *get_format_str (int type
)
509 case ARG_VOID
: return "void";
510 case ARG_FLOAT
: return "%f";
511 case ARG_DOUBLE
: return "%g";
512 case ARG_POINTER
: return "%p";
513 case ARG_WIDE_STRING
:
514 case ARG_STRING
: return "%s";
515 case ARG_LONG
: return "%ld";
516 case ARG_STRUCT
: return "struct";
523 /*******************************************************************
526 * Determin if a parameter is In or In/Out
528 static const char *get_in_or_out (const parsed_symbol
*sym
, size_t arg
)
530 assert (sym
&& arg
< sym
->argc
);
531 assert (globals
.do_documentation
);
533 if (sym
->arg_flag
[arg
] & CT_CONST
)
536 switch (sym
->arg_type
[arg
])
541 case ARG_STRUCT
: return "In";
543 case ARG_WIDE_STRING
:
544 case ARG_STRING
: return "In/Out";