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