Removed trailing whitespace.
[wine] / tools / winedump / main.c
1 /*
2  *  Option processing and main()
3  *
4  *  Copyright 2000 Jon Griffiths
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include "winedump.h"
21
22
23 _globals globals; /* All global variables */
24
25
26 static void do_include (const char *arg)
27 {
28   globals.directory = arg;
29   globals.do_code = 1;
30 }
31
32
33 static inline const char* strip_ext (const char *str)
34 {
35   char *ext = strstr(str, ".dll");
36   if (ext)
37     return str_substring (str, ext);
38   else
39     return strdup (str);
40 }
41
42
43 static void do_name (const char *arg)
44 {
45   globals.dll_name = strip_ext (arg);
46 }
47
48
49 static void do_spec (const char *arg)
50 {
51     if (globals.mode != NONE) fatal("Only one mode can be specified\n");
52     globals.mode = SPEC;
53 }
54
55
56 static void do_demangle (const char *arg)
57 {
58     if (globals.mode != NONE) fatal("Only one mode can be specified\n");
59     globals.mode = DMGL;
60     globals.do_code = 1;
61 }
62
63
64 static void do_dump (const char *arg)
65 {
66     if (globals.mode != NONE) fatal("Only one mode can be specified\n");
67     globals.mode = DUMP;
68     globals.do_code = 1;
69 }
70
71
72 static void do_code (void)
73 {
74   globals.do_code = 1;
75 }
76
77
78 static void do_trace (void)
79 {
80   globals.do_trace = 1;
81   globals.do_code = 1;
82 }
83
84
85 static void do_forward (const char *arg)
86 {
87   globals.forward_dll = arg;
88   globals.do_trace = 1;
89   globals.do_code = 1;
90 }
91
92 static void do_document (void)
93 {
94   globals.do_documentation = 1;
95 }
96
97 static void do_cdecl (void)
98 {
99   globals.do_cdecl = 1;
100 }
101
102
103 static void do_quiet (void)
104 {
105   globals.do_quiet = 1;
106 }
107
108
109 static void do_start (const char *arg)
110 {
111   globals.start_ordinal = atoi (arg);
112   if (!globals.start_ordinal)
113     fatal ("Invalid -s option (must be numeric)");
114 }
115
116
117 static void do_end (const char *arg)
118 {
119   globals.end_ordinal = atoi (arg);
120   if (!globals.end_ordinal)
121     fatal ("Invalid -e option (must be numeric)");
122 }
123
124
125 static void do_verbose (void)
126 {
127   globals.do_verbose = 1;
128 }
129
130
131 static void do_symdmngl (void)
132 {
133     globals.do_demangle = 1;
134 }
135
136 static void do_dumphead (void)
137 {
138     globals.do_dumpheader = 1;
139 }
140
141 static void do_dumpsect (const char* arg)
142 {
143     globals.dumpsect = arg;
144 }
145
146 static void do_dumpall(void)
147 {
148     globals.do_dumpheader = 1;
149     globals.dumpsect = "ALL";
150 }
151
152 struct option
153 {
154   const char *name;
155   Mode mode;
156   int   has_arg;
157   void  (*func) ();
158   const char *usage;
159 };
160
161 static const struct option option_table[] = {
162   {"-h",    NONE, 0, do_usage,    "-h           Display this help message"},
163   {"sym",   DMGL, 0, do_demangle, "sym <sym>    Demangle C++ symbol <sym> and exit"},
164   {"spec",  SPEC, 0, do_spec,     "spec <dll>   Use dll for input file and generate implementation code"},
165   {"-I",    SPEC, 1, do_include,  "-I dir       Look for prototypes in 'dir' (implies -c)"},
166   {"-c",    SPEC, 0, do_code,     "-c           Generate skeleton code (requires -I)"},
167   {"-t",    SPEC, 0, do_trace,    "-t           TRACE arguments (implies -c)"},
168   {"-f",    SPEC, 1, do_forward,  "-f dll       Forward calls to 'dll' (implies -t)"},
169   {"-D",    SPEC, 0, do_document, "-D           Generate documentation"},
170   {"-o",    SPEC, 1, do_name,     "-o name      Set the output dll name (default: dll)"},
171   {"-C",    SPEC, 0, do_cdecl,    "-C           Assume __cdecl calls (default: __stdcall)"},
172   {"-s",    SPEC, 1, do_start,    "-s num       Start prototype search after symbol 'num'"},
173   {"-e",    SPEC, 1, do_end,      "-e num       End prototype search after symbol 'num'"},
174   {"-q",    SPEC, 0, do_quiet,    "-q           Don't show progress (quiet)."},
175   {"-v",    SPEC, 0, do_verbose,  "-v           Show lots of detail while working (verbose)."},
176   {"dump",  DUMP, 0, do_dump,     "dump <mod>   Dumps the content of the module (dll, exe...) named <mod>"},
177   {"-C",    DUMP, 0, do_symdmngl, "-C           Turns on symbol demangling"},
178   {"-f",    DUMP, 0, do_dumphead, "-f           Dumps file header information"},
179   {"-j",    DUMP, 1, do_dumpsect, "-j sect_name Dumps only the content of section sect_name (import, export, debug)"},
180   {"-x",    DUMP, 0, do_dumpall,  "-x           Dumps everything"},
181   {NULL,    NONE, 0, NULL,        NULL}
182 };
183
184 void do_usage (void)
185 {
186     const struct option *opt;
187     printf ("Usage: winedump [-h | sym <sym> | spec <dll> | dump <dll>]\n");
188     printf ("Mode options (can be put as the mode (sym/spec/dump...) is declared):\n");
189     printf ("\tWhen used in -h mode\n");
190     for (opt = option_table; opt->name; opt++)
191         if (opt->mode == NONE)
192             printf ("\t   %s\n", opt->usage);
193     printf ("\tWhen used in sym mode\n");
194     for (opt = option_table; opt->name; opt++)
195         if (opt->mode == DMGL)
196             printf ("\t   %s\n", opt->usage);
197     printf ("\tWhen used in spec mode\n");
198     for (opt = option_table; opt->name; opt++)
199         if (opt->mode == SPEC)
200             printf ("\t   %s\n", opt->usage);
201     printf ("\tWhen used in dump mode\n");
202     for (opt = option_table; opt->name; opt++)
203         if (opt->mode == DUMP)
204             printf ("\t   %s\n", opt->usage);
205
206     puts ("\n");
207     exit (1);
208 }
209
210
211 /*******************************************************************
212  *          parse_options
213  *
214  * Parse options from the argv array
215  */
216 static void parse_options (char *argv[])
217 {
218   const struct option *opt;
219   char *const *ptr;
220   const char *arg = NULL;
221
222   ptr = argv + 1;
223
224   while (*ptr != NULL)
225   {
226     for (opt = option_table; opt->name; opt++)
227     {
228      if (globals.mode != NONE && opt->mode != NONE && globals.mode != opt->mode)
229        continue;
230      if (((opt->has_arg == 1) && !strncmp (*ptr, opt->name, strlen (opt->name))) ||
231          ((opt->has_arg == 2) && !strcmp (*ptr, opt->name)))
232       {
233         arg = *ptr + strlen (opt->name);
234         if (*arg == '\0') arg = *++ptr;
235         break;
236       }
237       if (!strcmp (*ptr, opt->name))
238       {
239         arg = NULL;
240         break;
241       }
242     }
243
244     if (!opt->name)
245     {
246         if ((*ptr)[0] == '-')
247             fatal ("Unrecognized option");
248         if (globals.input_name != NULL)
249             fatal ("Only one file can be treated at once");
250         globals.input_name = *ptr;
251     }
252     else if (opt->has_arg && arg != NULL)
253         opt->func (arg);
254     else
255         opt->func ("");
256
257     ptr++;
258   }
259
260   if (globals.mode == SPEC && globals.do_code && !globals.directory)
261     fatal ("-I must be used if generating code");
262
263   if (VERBOSE && QUIET)
264     fatal ("Options -v and -q are mutually exclusive");
265 }
266
267 static void set_module_name(unsigned setUC)
268 {
269     const char* ptr;
270     char*       buf;
271     int         len;
272
273     /* FIXME: we shouldn't assume all module extensions are .dll in winedump
274      * in some cases, we could have some .drv for example
275      */
276     /* get module name from name */
277     if ((ptr = strrchr (globals.input_name, '/')))
278         ptr++;
279     else
280         ptr = globals.input_name;
281     len = strlen(ptr);
282     if (len > 4 && strcmp(ptr + len - 4, ".dll") == 0)
283         len -= 4;
284     buf = malloc(len + 1);
285     memcpy(buf, (void*)ptr, len);
286     buf[len] = 0;
287     globals.input_module = buf;
288     OUTPUT_UC_DLL_NAME = (setUC) ? str_toupper( strdup (OUTPUT_DLL_NAME)) : "";
289 }
290
291 /*******************************************************************
292  *         main
293  */
294 #ifdef __GNUC__
295 int   main (int argc __attribute__((unused)), char *argv[])
296 #else
297 int   main (int argc, char *argv[])
298 #endif
299 {
300     parsed_symbol symbol;
301     int count = 0;
302
303     globals.mode = NONE;
304     globals.forward_dll = NULL;
305     globals.input_name = NULL;
306
307     parse_options (argv);
308
309     memset (&symbol, 0, sizeof (parsed_symbol));
310
311     switch (globals.mode)
312     {
313     case DMGL:
314         globals.uc_dll_name = "";
315         VERBOSE = 1;
316
317         symbol_init (&symbol, globals.input_name);
318         globals.input_module = "";
319         if (symbol_demangle (&symbol) == -1)
320             fatal( "Symbol hasn't got a mangled name\n");
321         if (symbol.flags & SYM_DATA)
322             printf (symbol.arg_text[0]);
323         else
324             output_prototype (stdout, &symbol);
325         fputc ('\n', stdout);
326         symbol_clear(&symbol);
327         break;
328
329     case SPEC:
330         set_module_name(1);
331         dll_open (globals.input_name);
332
333         output_spec_preamble ();
334         output_header_preamble ();
335         output_c_preamble ();
336
337         while (!dll_next_symbol (&symbol))
338         {
339             count++;
340
341             if (NORMAL)
342                 printf ("Export %3d - '%s' ...%c", count, symbol.symbol,
343                         VERBOSE ? '\n' : ' ');
344
345             if (globals.do_code && count >= globals.start_ordinal
346                 && (!globals.end_ordinal || count <= globals.end_ordinal))
347             {
348                 /* Attempt to get information about the symbol */
349                 int result = symbol_demangle (&symbol);
350
351                 if (result)
352                     result = symbol_search (&symbol);
353
354                 if (!result && symbol.function_name)
355                     /* Clean up the prototype */
356                     symbol_clean_string (symbol.function_name);
357
358                 if (NORMAL)
359                     puts (result ? "[Not Found]" : "[OK]");
360             }
361             else if (NORMAL)
362                 puts ("[Ignoring]");
363
364             output_spec_symbol (&symbol);
365             output_header_symbol (&symbol);
366             output_c_symbol (&symbol);
367
368             symbol_clear (&symbol);
369         }
370
371         output_makefile ();
372         output_install_script ();
373
374         if (VERBOSE)
375             puts ("Finished, Cleaning up...");
376         break;
377     case NONE:
378         do_usage();
379         break;
380     case DUMP:
381         set_module_name(0);
382         dump_file(globals.input_name);
383         break;
384     }
385
386     return 0;
387 }