Moved all references to file descriptors out of the generic object
[wine] / tools / winebuild / main.c
1 /*
2  * Main function
3  *
4  * Copyright 1993 Robert J. Amstadt
5  * Copyright 1995 Martin von Loewis
6  * Copyright 1995, 1996, 1997 Alexandre Julliard
7  * Copyright 1997 Eric Youngdale
8  * Copyright 1999 Ulrich Weigand
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  */
24
25 #include "config.h"
26 #include "wine/port.h"
27
28 #include <assert.h>
29 #include <stdio.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <ctype.h>
33
34 #include "build.h"
35
36 ORDDEF *EntryPoints[MAX_ORDINALS];
37 ORDDEF *Ordinals[MAX_ORDINALS];
38 ORDDEF *Names[MAX_ORDINALS];
39
40 SPEC_MODE SpecMode = SPEC_MODE_DLL;
41 SPEC_TYPE SpecType = SPEC_WIN32;
42
43 int Base = MAX_ORDINALS;
44 int Limit = 0;
45 int DLLHeapSize = 0;
46 int UsePIC = 0;
47 int stack_size = 0;
48 int nb_entry_points = 0;
49 int nb_names = 0;
50 int nb_debug_channels = 0;
51 int nb_lib_paths = 0;
52 int display_warnings = 0;
53 int kill_at = 0;
54
55 /* we only support relay debugging on i386 */
56 #if defined(__i386__) && !defined(NO_TRACE_MSGS)
57 int debugging = 1;
58 #else
59 int debugging = 0;
60 #endif
61
62 char DLLName[80];
63 char DLLFileName[80];
64 char owner_name[80];
65 char *init_func = NULL;
66 char **debug_channels = NULL;
67 char **lib_path = NULL;
68
69 char *input_file_name = NULL;
70 const char *output_file_name = NULL;
71
72 static FILE *input_file;
73 static FILE *output_file;
74 static const char *current_src_dir;
75 static int nb_res_files;
76 static char **res_files;
77
78 /* execution mode */
79 static enum
80 {
81     MODE_NONE,
82     MODE_SPEC,
83     MODE_EXE,
84     MODE_GLUE,
85     MODE_DEF,
86     MODE_DEBUG,
87     MODE_RELAY16,
88     MODE_RELAY32
89 } exec_mode = MODE_NONE;
90
91 /* set the dll file name from the input file name */
92 static void set_dll_file_name( const char *name )
93 {
94     char *p;
95
96     if (*DLLFileName) return;
97
98     if ((p = strrchr( name, '\\' ))) name = p + 1;
99     if ((p = strrchr( name, '/' ))) name = p + 1;
100     strcpy( DLLFileName, name );
101     if ((p = strrchr( DLLFileName, '.' )) && !strcmp( p, ".spec" )) *p = 0;
102     if (!strchr( DLLFileName, '.' )) strcat( DLLFileName, ".dll" );
103 }
104
105 /* cleanup on program exit */
106 static void cleanup(void)
107 {
108     if (output_file_name) unlink( output_file_name );
109 }
110
111
112 /*******************************************************************
113  *         command-line option handling
114  */
115
116 struct option_descr
117 {
118     const char *name;
119     int         has_arg;
120     void      (*func)();
121     const char *usage;
122 };
123
124 static void do_output( const char *arg );
125 static void do_usage(void);
126 static void do_warnings(void);
127 static void do_f_flags( const char *arg );
128 static void do_define( const char *arg );
129 static void do_include( const char *arg );
130 static void do_k_flags( const char *arg );
131 static void do_ignore( const char *arg );
132 static void do_kill_at(void);
133 static void do_exe_mode( const char *arg );
134 static void do_module( const char *arg );
135 static void do_heap( const char *arg );
136 static void do_name( const char *arg );
137 static void do_file( const char *arg );
138 static void do_entry( const char *arg );
139 static void do_spec( const char *arg );
140 static void do_def( const char *arg );
141 static void do_exe( const char *arg );
142 static void do_glue(void);
143 static void do_relay16(void);
144 static void do_relay32(void);
145 static void do_debug(void);
146 static void do_chdir( const char *arg );
147 static void do_lib( const char *arg );
148 static void do_import( const char *arg );
149 static void do_dimport( const char *arg );
150 static void do_rsrc( const char *arg );
151
152 static const struct option_descr option_table[] =
153 {
154     { "-h",        0, do_usage,   "-h               Display this help message" },
155     { "-w",        0, do_warnings,"-w               Turn on warnings" },
156     { "-C",        1, do_chdir,   "-C dir           Change directory to <dir> before opening source files" },
157     { "-f",        1, do_f_flags, "-f flags         Compiler flags (only -fPIC is supported)" },
158     { "-D",        1, do_define,  "-D sym           Ignored for C flags compatibility" },
159     { "-I",        1, do_include, "-I dir           Ignored for C flags compatibility" },
160     { "-K",        1, do_k_flags, "-K flags         Compiler flags (only -KPIC is supported)" },
161     { "-i",        1, do_ignore,  "-i sym[,sym]     Ignore specified symbols when resolving imports" },
162     { "-k",        0, do_kill_at, "-k               Kill stdcall decorations in generated .def files" },
163     { "-m",        1, do_exe_mode,"-m mode          Set the executable mode (cui|gui|cuiw|guiw)" },
164     { "-M",        1, do_module,  "-M module        Set the name of the main (Win32) module for a Win16 dll" },
165     { "-L",        1, do_lib,     "-L directory     Look for imports libraries in 'directory'" },
166     { "-l",        1, do_import,  "-l lib.dll       Import the specified library" },
167     { "-d",        1, do_dimport, "-d lib.dll       Delay-import the specified library" },
168     { "-H",        1, do_heap,    "-H size          Set the heap size for a Win16 dll" },
169     { "-N",        1, do_name,    "-N dllname       Set the DLL name (default: set from input file name)" },
170     { "-F",        1, do_file,    "-F dllfile       Set the DLL filename (default: set from input file name)" },
171     { "-e",        1, do_entry,   "-e function      Set the DLL entry point function (default: DllMain)" },
172     { "-r",        1, do_rsrc,    "-r rsrc.res      Load resources from rsrc.res" },
173     { "-res",      1, do_rsrc,    NULL },  /* for backwards compatibility, will disappear */
174     { "-o",        1, do_output,  "-o name          Set the output file name (default: stdout)\n" },
175     { "--spec",    1, do_spec,    "--spec file.spec Build a .c file from a spec file" },
176     { "--def",     1, do_def,     "--def file.spec  Build a .def file from a spec file" },
177     { "--exe",     1, do_exe,     "--exe name       Build a .c file for the named executable" },
178     { "--debug",   0, do_debug,   "--debug [files]  Build a .c file containing debug channels declarations" },
179     { "--glue",    0, do_glue,    "--glue [files]   Build the 16-bit glue for the source files" },
180     { "--relay16", 0, do_relay16, "--relay16        Build the 16-bit relay assembly routines" },
181     { "--relay32", 0, do_relay32, "--relay32        Build the 32-bit relay assembly routines" },
182     { NULL,       0, NULL,      NULL }
183 };
184
185 static void do_output( const char *arg )
186 {
187     if ( ( unlink ( arg ) ) == -1 && ( errno != ENOENT ) )
188     {
189         fprintf ( stderr, "Unable to create output file '%s'\n", arg );
190         exit (1);
191     }
192     if (!(output_file = fopen( arg, "w" )))
193     {
194         fprintf( stderr, "Unable to create output file '%s'\n", arg );
195         exit(1);
196     }
197     output_file_name = arg;
198     atexit( cleanup );  /* make sure we remove the output file on exit */
199 }
200
201 static void do_usage(void)
202 {
203     const struct option_descr *opt;
204     fprintf( stderr, "Usage: winebuild [options]\n\n" );
205     fprintf( stderr, "Options:\n" );
206     for (opt = option_table; opt->name; opt++)
207         if (opt->usage) fprintf( stderr, "   %s\n", opt->usage );
208
209     fprintf( stderr, "\nExactly one of --spec, --def, --exe, --debug, --glue, --relay16 or --relay32 must be specified.\n\n" );
210     exit(1);
211 }
212
213 static void do_warnings(void)
214 {
215     display_warnings = 1;
216 }
217
218 static void do_f_flags( const char *arg )
219 {
220     if (!strcmp( arg, "PIC" )) UsePIC = 1;
221     /* ignore all other flags */
222 }
223
224 static void do_define( const char *arg )
225 {
226     /* nothing */
227 }
228
229 static void do_include( const char *arg )
230 {
231     /* nothing */
232 }
233
234 static void do_k_flags( const char *arg )
235 {
236     /* Ignored, because cc generates correct code. */
237     /* if (!strcmp( arg, "PIC" )) UsePIC = 1; */
238     /* ignore all other flags */
239 }
240
241 static void do_ignore( const char *arg )
242 {
243     char *str = xstrdup( arg );
244     char *token = strtok( str, "," );
245     while (token)
246     {
247         add_ignore_symbol( token );
248         token = strtok( NULL, "," );
249     }
250     free( str );
251 }
252
253 static void do_kill_at(void)
254 {
255     kill_at = 1;
256 }
257
258 static void do_heap( const char *arg )
259 {
260     if (!isdigit(arg[0]))
261         fatal_error( "Expected number argument with -H option instead of '%s'\n", arg );
262     DLLHeapSize = atoi(arg);
263     if (DLLHeapSize > 65535) fatal_error( "Invalid heap size %d, maximum is 65535\n", DLLHeapSize );
264 }
265
266 static void do_name( const char *arg )
267 {
268     strncpy( DLLName, arg, sizeof(DLLName) );
269     DLLName[sizeof(DLLName) - 1] = 0;
270 }
271
272 static void do_file( const char *arg )
273 {
274     strncpy( DLLFileName, arg, sizeof(DLLFileName) );
275     DLLFileName[sizeof(DLLFileName) - 1] = 0;
276 }
277
278 static void do_entry( const char *arg )
279 {
280     init_func = xstrdup( arg );
281 }
282
283 static void do_spec( const char *arg )
284 {
285     if (exec_mode != MODE_NONE || !arg[0]) do_usage();
286     exec_mode = MODE_SPEC;
287     input_file = open_input_file( NULL, arg );
288     set_dll_file_name( arg );
289 }
290
291 static void do_def( const char *arg )
292 {
293     if (exec_mode != MODE_NONE || !arg[0]) do_usage();
294     exec_mode = MODE_DEF;
295     input_file = open_input_file( NULL, arg );
296     set_dll_file_name( arg );
297 }
298
299 static void do_exe( const char *arg )
300 {
301     const char *p;
302
303     if (exec_mode != MODE_NONE || !arg[0]) do_usage();
304     exec_mode = MODE_EXE;
305     if ((p = strrchr( arg, '/' ))) p++;
306     else p = arg;
307     strcpy( DLLFileName, p );
308     if (!strchr( DLLFileName, '.' )) strcat( DLLFileName, ".exe" );
309     if (SpecMode == SPEC_MODE_DLL) SpecMode = SPEC_MODE_GUIEXE;
310 }
311
312 static void do_exe_mode( const char *arg )
313 {
314     if (!strcmp( arg, "gui" )) SpecMode = SPEC_MODE_GUIEXE;
315     else if (!strcmp( arg, "cui" )) SpecMode = SPEC_MODE_CUIEXE;
316     else if (!strcmp( arg, "guiw" )) SpecMode = SPEC_MODE_GUIEXE_UNICODE;
317     else if (!strcmp( arg, "cuiw" )) SpecMode = SPEC_MODE_CUIEXE_UNICODE;
318     else do_usage();
319 }
320
321 static void do_module( const char *arg )
322 {
323     strcpy( owner_name, arg );
324     SpecType = SPEC_WIN16;
325 }
326
327 static void do_glue(void)
328 {
329     if (exec_mode != MODE_NONE) do_usage();
330     exec_mode = MODE_GLUE;
331 }
332
333 static void do_debug(void)
334 {
335     if (exec_mode != MODE_NONE) do_usage();
336     exec_mode = MODE_DEBUG;
337 }
338
339 static void do_chdir( const char *arg )
340 {
341     current_src_dir = arg;
342 }
343
344 static void do_relay16(void)
345 {
346     if (exec_mode != MODE_NONE) do_usage();
347     exec_mode = MODE_RELAY16;
348 }
349
350 static void do_relay32(void)
351 {
352     if (exec_mode != MODE_NONE) do_usage();
353     exec_mode = MODE_RELAY32;
354 }
355
356 static void do_lib( const char *arg )
357 {
358     lib_path = xrealloc( lib_path, (nb_lib_paths+1) * sizeof(*lib_path) );
359     lib_path[nb_lib_paths++] = xstrdup( arg );
360 }
361
362 static void do_import( const char *arg )
363 {
364     add_import_dll( arg, 0 );
365 }
366
367 static void do_dimport( const char *arg )
368 {
369     add_import_dll( arg, 1 );
370 }
371
372 static void do_rsrc( const char *arg )
373 {
374     res_files = xrealloc( res_files, (nb_res_files+1) * sizeof(*res_files) );
375     res_files[nb_res_files++] = xstrdup( arg );
376 }
377
378 /* parse options from the argv array and remove all the recognized ones */
379 static void parse_options( char *argv[] )
380 {
381     const struct option_descr *opt;
382     char **ptr, **last;
383     const char* arg=NULL;
384
385     for (ptr = last = argv; *ptr; ptr++)
386     {
387         /* first check the exact option name */
388         for (opt = option_table; opt->name; opt++)
389         {
390             if (!strcmp( *ptr, opt->name ) ||
391                 /* for long option check without the first dash too */
392                 (opt->name[1] == '-' && !strcmp( *ptr, opt->name+1 )))
393             {
394                 if (opt->has_arg) arg = *(++ptr);
395                 else arg = NULL;
396                 break;
397             }
398         }
399
400         /* now check for option name concatenated with argument */
401         if (!opt->name)
402         {
403             for (opt = option_table; opt->name; opt++)
404             {
405                 if (opt->has_arg && !strncmp( *ptr, opt->name, strlen(opt->name) ))
406                 {
407                     arg = *ptr + strlen(opt->name);
408                     break;
409                 }
410             }
411         }
412
413         if (opt->name)
414         {
415             if (opt->has_arg && arg != NULL) opt->func( arg );
416             else opt->func( "" );
417         }
418         else  /* keep this argument */
419         {
420             if (last != ptr) *last = *ptr;
421             last++;
422         }
423     }
424     *last = NULL;
425 }
426
427
428 /* load all specified resource files */
429 static void load_resources( char *argv[] )
430 {
431     int i;
432     char **ptr, **last;
433
434     switch (SpecType)
435     {
436     case SPEC_WIN16:
437         for (i = 0; i < nb_res_files; i++) load_res16_file( res_files[i] );
438         break;
439
440     case SPEC_WIN32:
441         for (i = 0; i < nb_res_files; i++)
442         {
443             if (!load_res32_file( res_files[i] ))
444                 fatal_error( "%s is not a valid Win32 resource file\n", res_files[i] );
445         }
446
447         /* load any resource file found in the remaining arguments */
448         for (ptr = last = argv; *ptr; ptr++)
449         {
450             if (!load_res32_file( *ptr ))
451                 *last++ = *ptr; /* not a resource file, keep it in the list */
452         }
453         *last = NULL;
454         break;
455     }
456 }
457
458 /*******************************************************************
459  *         main
460  */
461 int main(int argc, char **argv)
462 {
463     output_file = stdout;
464     parse_options( argv + 1 );
465
466     switch(exec_mode)
467     {
468     case MODE_SPEC:
469         load_resources( argv + 1 );
470         ParseTopLevel( input_file );
471         switch (SpecType)
472         {
473             case SPEC_WIN16:
474                 if (argv[1])
475                     fatal_error( "file argument '%s' not allowed in this mode\n", argv[1] );
476                 BuildSpec16File( output_file );
477                 break;
478             case SPEC_WIN32:
479                 read_undef_symbols( argv + 1 );
480                 BuildSpec32File( output_file );
481                 break;
482             default: assert(0);
483         }
484         break;
485     case MODE_EXE:
486         if (SpecType == SPEC_WIN16) fatal_error( "Cannot build 16-bit exe files\n" );
487         load_resources( argv + 1 );
488         read_undef_symbols( argv + 1 );
489         BuildSpec32File( output_file );
490         break;
491     case MODE_DEF:
492         if (argv[1]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[1] );
493         if (SpecType == SPEC_WIN16) fatal_error( "Cannot yet build .def file for 16-bit dlls\n" );
494         ParseTopLevel( input_file );
495         BuildDef32File( output_file );
496         break;
497     case MODE_DEBUG:
498         BuildDebugFile( output_file, current_src_dir, argv + 1 );
499         break;
500     case MODE_GLUE:
501         BuildGlue( output_file, current_src_dir, argv + 1 );
502         break;
503     case MODE_RELAY16:
504         if (argv[1]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[1] );
505         BuildRelays16( output_file );
506         break;
507     case MODE_RELAY32:
508         if (argv[1]) fatal_error( "file argument '%s' not allowed in this mode\n", argv[1] );
509         BuildRelays32( output_file );
510         break;
511     default:
512         do_usage();
513         break;
514     }
515     if (output_file_name)
516     {
517         fclose( output_file );
518         output_file_name = NULL;
519     }
520     return 0;
521 }