winedump: Dump the EMF files as any other file types.
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include "winedump.h"
25
26 _globals globals; /* All global variables */
27
28
29 static void do_include (const char *arg)
30 {
31   char *newIncludes;
32
33   if (!globals.directory)
34     globals.directory = strdup(arg);
35   else {
36     newIncludes = str_create (3,globals.directory," ",arg);
37     free(globals.directory);
38     globals.directory = newIncludes;
39   }
40   globals.do_code = 1;
41 }
42
43
44 static inline const char* strip_ext (const char *str)
45 {
46   int len = strlen(str);
47   if (len>4 && strcmp(str+len-4,".dll") == 0)
48     return str_substring (str, str+len-4);
49   else
50     return strdup (str);
51 }
52
53
54 static void do_name (const char *arg)
55 {
56   globals.dll_name = strip_ext (arg);
57 }
58
59
60 static void do_spec (const char *arg)
61 {
62     if (globals.mode != NONE) fatal("Only one mode can be specified\n");
63     globals.mode = SPEC;
64 }
65
66
67 static void do_demangle (const char *arg)
68 {
69     if (globals.mode != NONE) fatal("Only one mode can be specified\n");
70     globals.mode = DMGL;
71     globals.do_code = 1;
72 }
73
74
75 static void do_dump (const char *arg)
76 {
77     if (globals.mode != NONE) fatal("Only one mode can be specified\n");
78     globals.mode = DUMP;
79     globals.do_code = 1;
80 }
81
82
83 static void do_code (void)
84 {
85   globals.do_code = 1;
86 }
87
88
89 static void do_trace (void)
90 {
91   globals.do_trace = 1;
92   globals.do_code = 1;
93 }
94
95
96 static void do_forward (const char *arg)
97 {
98   globals.forward_dll = arg;
99   globals.do_trace = 1;
100   globals.do_code = 1;
101 }
102
103 static void do_document (void)
104 {
105   globals.do_documentation = 1;
106 }
107
108 static void do_cdecl (void)
109 {
110   globals.do_cdecl = 1;
111 }
112
113
114 static void do_quiet (void)
115 {
116   globals.do_quiet = 1;
117 }
118
119
120 static void do_start (const char *arg)
121 {
122   globals.start_ordinal = atoi (arg);
123   if (!globals.start_ordinal)
124     fatal ("Invalid -s option (must be numeric)");
125 }
126
127
128 static void do_end (const char *arg)
129 {
130   globals.end_ordinal = atoi (arg);
131   if (!globals.end_ordinal)
132     fatal ("Invalid -e option (must be numeric)");
133 }
134
135
136 static void do_symfile (const char *arg)
137 {
138   FILE *f;
139   char symstring[256];    /* keep count with "%<width>s" below */
140   search_symbol *symbolp,**symbolptail = &globals.search_symbol;
141
142   if (!(f = fopen(arg, "rt")))
143     fatal ("Cannot open <symfile>");
144   while (1 == fscanf(f, "%255s", symstring))    /* keep count with [<width>] above */
145   {
146     symstring[sizeof(symstring)-1] = '\0';
147     if (!(symbolp = malloc(sizeof(*symbolp) + strlen(symstring))))
148       fatal ("Out of memory");
149     strcpy(symbolp->symbolname, symstring);
150     symbolp->found = 0;
151     symbolp->next = NULL;
152     *symbolptail = symbolp;
153     symbolptail = &symbolp->next;
154   }
155   if (fclose(f))
156     fatal ("Cannot close <symfile>");
157 }
158
159
160 static void do_verbose (void)
161 {
162   globals.do_verbose = 1;
163 }
164
165
166 static void do_symdmngl (void)
167 {
168     globals.do_demangle = 1;
169 }
170
171 static void do_dumphead (void)
172 {
173     globals.do_dumpheader = 1;
174 }
175
176 static void do_dumpsect (const char* arg)
177 {
178     globals.dumpsect = arg;
179 }
180
181 static void do_rawdebug (void)
182 {
183     globals.do_debug = 1;
184 }
185
186 static void do_dumpall(void)
187 {
188     globals.do_dumpheader = 1;
189     globals.dumpsect = "ALL";
190 }
191
192 struct my_option
193 {
194   const char *name;
195   Mode mode;
196   int   has_arg;
197   void  (*func) ();
198   const char *usage;
199 };
200
201 static const struct my_option option_table[] = {
202   {"--help",NONE, 0, do_usage,    "--help       Display this help message"},
203   {"-h",    NONE, 0, do_usage,    "-h           Synonym for --help"},
204   {"-?",    NONE, 0, do_usage,    "-?           Synonym for --help"},
205   {"sym",   DMGL, 0, do_demangle, "sym <sym>    Demangle C++ symbol <sym> and exit"},
206   {"spec",  SPEC, 0, do_spec,     "spec <dll>   Use dll for input file and generate implementation code"},
207   {"-I",    SPEC, 1, do_include,  "-I dir       Look for prototypes in 'dir' (implies -c)"},
208   {"-c",    SPEC, 0, do_code,     "-c           Generate skeleton code (requires -I)"},
209   {"-t",    SPEC, 0, do_trace,    "-t           TRACE arguments (implies -c)"},
210   {"-f",    SPEC, 1, do_forward,  "-f dll       Forward calls to 'dll' (implies -t)"},
211   {"-D",    SPEC, 0, do_document, "-D           Generate documentation"},
212   {"-o",    SPEC, 1, do_name,     "-o name      Set the output dll name (default: dll). note: strips .dll extensions"},
213   {"-C",    SPEC, 0, do_cdecl,    "-C           Assume __cdecl calls (default: __stdcall)"},
214   {"-s",    SPEC, 1, do_start,    "-s num       Start prototype search after symbol 'num'"},
215   {"-e",    SPEC, 1, do_end,      "-e num       End prototype search after symbol 'num'"},
216   {"-S",    SPEC, 1, do_symfile,  "-S symfile   Search only prototype names found in 'symfile'"},
217   {"-q",    SPEC, 0, do_quiet,    "-q           Don't show progress (quiet)."},
218   {"-v",    SPEC, 0, do_verbose,  "-v           Show lots of detail while working (verbose)."},
219   {"dump",  DUMP, 0, do_dump,     "dump <file>  Dumps the contents of a file (dll, exe, lib...)"},
220   {"-C",    DUMP, 0, do_symdmngl, "-C           Turns on symbol demangling"},
221   {"-f",    DUMP, 0, do_dumphead, "-f           Dumps file header information"},
222   {"-G",    DUMP, 0, do_rawdebug, "-G           Dumps raw debug information"},
223   {"-j",    DUMP, 1, do_dumpsect, "-j sect_name Dumps only the content of section sect_name (import, export, debug, resource, tls)"},
224   {"-x",    DUMP, 0, do_dumpall,  "-x           Dumps everything"},
225   {NULL,    NONE, 0, NULL,        NULL}
226 };
227
228 void do_usage (void)
229 {
230     const struct my_option *opt;
231     printf ("Usage: winedump [-h | sym <sym> | spec <dll> | dump <file>]\n");
232     printf ("Mode options (can be put as the mode (sym/spec/dump...) is declared):\n");
233     printf ("\tWhen used in --help mode\n");
234     for (opt = option_table; opt->name; opt++)
235         if (opt->mode == NONE)
236             printf ("\t   %s\n", opt->usage);
237     printf ("\tWhen used in sym mode\n");
238     for (opt = option_table; opt->name; opt++)
239         if (opt->mode == DMGL)
240             printf ("\t   %s\n", opt->usage);
241     printf ("\tWhen used in spec mode\n");
242     for (opt = option_table; opt->name; opt++)
243         if (opt->mode == SPEC)
244             printf ("\t   %s\n", opt->usage);
245     printf ("\tWhen used in dump mode\n");
246     for (opt = option_table; opt->name; opt++)
247         if (opt->mode == DUMP)
248             printf ("\t   %s\n", opt->usage);
249
250     puts ("");
251     exit (1);
252 }
253
254
255 /*******************************************************************
256  *          parse_options
257  *
258  * Parse options from the argv array
259  */
260 static void parse_options (char *argv[])
261 {
262   const struct my_option *opt;
263   char *const *ptr;
264   const char *arg = NULL;
265
266   ptr = argv + 1;
267
268   while (*ptr != NULL)
269   {
270     for (opt = option_table; opt->name; opt++)
271     {
272      if (globals.mode != NONE && opt->mode != NONE && globals.mode != opt->mode)
273        continue;
274      if (((opt->has_arg == 1) && !strncmp (*ptr, opt->name, strlen (opt->name))) ||
275          ((opt->has_arg == 2) && !strcmp (*ptr, opt->name)))
276       {
277         arg = *ptr + strlen (opt->name);
278         if (*arg == '\0') arg = *++ptr;
279         break;
280       }
281       if (!strcmp (*ptr, opt->name))
282       {
283         arg = NULL;
284         break;
285       }
286     }
287
288     if (!opt->name)
289     {
290         if ((*ptr)[0] == '-')
291             fatal ("Unrecognized option");
292         if (globals.input_name != NULL)
293             fatal ("Only one file can be treated at once");
294         globals.input_name = *ptr;
295     }
296     else if (opt->has_arg && arg != NULL)
297         opt->func (arg);
298     else
299         opt->func ("");
300
301     ptr++;
302   }
303
304   if (globals.mode == SPEC && globals.do_code && !globals.directory)
305     fatal ("-I must be used if generating code");
306
307   if (VERBOSE && QUIET)
308     fatal ("Options -v and -q are mutually exclusive");
309 }
310
311 static void set_module_name(unsigned setUC)
312 {
313     const char* ptr;
314     char*       buf;
315     int         len;
316
317     /* FIXME: we shouldn't assume all module extensions are .dll in winedump
318      * in some cases, we could have some .drv for example
319      */
320     /* get module name from name */
321     if ((ptr = strrchr (globals.input_name, '/')))
322         ptr++;
323     else
324         ptr = globals.input_name;
325     len = strlen(ptr);
326     if (len > 4 && strcmp(ptr + len - 4, ".dll") == 0)
327         len -= 4;
328     buf = malloc(len + 1);
329     memcpy(buf, (const void*)ptr, len);
330     buf[len] = 0;
331     globals.input_module = buf;
332     OUTPUT_UC_DLL_NAME = (setUC) ? str_toupper( strdup (OUTPUT_DLL_NAME)) : "";
333 }
334
335 /* Marks the symbol as 'found'! */
336 /* return: perform-search */
337 static int symbol_searched(int count, const char *symbolname)
338 {
339     search_symbol *search_symbol;
340
341     if (!(count >= globals.start_ordinal
342           && (!globals.end_ordinal || count <= globals.end_ordinal)))
343         return 0;
344     if (!globals.search_symbol)
345         return 1;
346     for (search_symbol = globals.search_symbol;
347          search_symbol;
348          search_symbol = search_symbol->next)
349     {
350         if (!strcmp(symbolname, search_symbol->symbolname))
351         {
352             search_symbol->found = 1;
353             return 1;
354         }
355     }
356     return 0;
357 }
358
359 /* return: some symbols weren't found */
360 static int symbol_finish(void)
361 {
362     const search_symbol *search_symbol;
363     int started = 0;
364
365     for (search_symbol = globals.search_symbol;
366          search_symbol;
367          search_symbol = search_symbol->next)
368     {
369         if (search_symbol->found)
370             continue;
371         if (!started)
372         {
373             /* stderr? not a practice here */
374             puts("These requested <symfile> symbols weren't found:");
375             started = 1;
376         }
377         printf("\t%s\n",search_symbol->symbolname);
378     }
379     return started;
380 }
381
382 /*******************************************************************
383  *         main
384  */
385 #ifdef __GNUC__
386 int   main (int argc __attribute__((unused)), char *argv[])
387 #else
388 int   main (int argc, char *argv[])
389 #endif
390 {
391     parsed_symbol symbol;
392     int count = 0;
393
394     globals.mode = NONE;
395     globals.forward_dll = NULL;
396     globals.input_name = NULL;
397
398     parse_options (argv);
399
400     memset (&symbol, 0, sizeof (parsed_symbol));
401
402     switch (globals.mode)
403     {
404     case DMGL:
405         globals.uc_dll_name = "";
406         VERBOSE = 1;
407
408         symbol_init (&symbol, globals.input_name);
409         globals.input_module = "";
410         if (symbol_demangle (&symbol) == -1)
411             fatal( "Symbol hasn't got a mangled name\n");
412         if (symbol.flags & SYM_DATA)
413             printf (symbol.arg_text[0]);
414         else
415             output_prototype (stdout, &symbol);
416         fputc ('\n', stdout);
417         symbol_clear(&symbol);
418         break;
419
420     case SPEC:
421         if (globals.input_name == NULL)
422             fatal("No file name has been given\n");
423         set_module_name(1);
424         if (!dll_open (globals.input_name))
425             break;
426
427         output_spec_preamble ();
428         output_header_preamble ();
429         output_c_preamble ();
430
431         while (!dll_next_symbol (&symbol))
432         {
433             count++;
434
435             if (NORMAL)
436                 printf ("Export %3d - '%s' ...%c", count, symbol.symbol,
437                         VERBOSE ? '\n' : ' ');
438
439             if (globals.do_code && symbol_searched(count, symbol.symbol))
440             {
441                 /* Attempt to get information about the symbol */
442                 int result = symbol_demangle (&symbol);
443
444                 if (result)
445                     result = symbol_search (&symbol);
446
447                 if (!result && symbol.function_name)
448                     /* Clean up the prototype */
449                     symbol_clean_string (symbol.function_name);
450
451                 if (NORMAL)
452                     puts (result ? "[Not Found]" : "[OK]");
453             }
454             else if (NORMAL)
455                 puts ("[Ignoring]");
456
457             output_spec_symbol (&symbol);
458             output_header_symbol (&symbol);
459             output_c_symbol (&symbol);
460
461             symbol_clear (&symbol);
462         }
463
464         output_makefile ();
465
466         if (VERBOSE)
467             puts ("Finished, Cleaning up...");
468         if (symbol_finish())
469             return 1;
470         break;
471     case NONE:
472         do_usage();
473         break;
474     case DUMP:
475         if (globals.input_name == NULL)
476             fatal("No file name has been given\n");
477         set_module_name(0);
478         dump_file(globals.input_name);
479         break;
480     }
481
482     return 0;
483 }