makefiles: Use the generic install flags for the tools directories.
[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     globals.do_demangle = 1;
73 }
74
75
76 static void do_dump (const char *arg)
77 {
78     if (globals.mode != NONE) fatal("Only one mode can be specified\n");
79     globals.mode = DUMP;
80     globals.do_code = 1;
81 }
82
83
84 static void do_code (const char *arg)
85 {
86   globals.do_code = 1;
87 }
88
89
90 static void do_trace (const char *arg)
91 {
92   globals.do_trace = 1;
93   globals.do_code = 1;
94 }
95
96
97 static void do_forward (const char *arg)
98 {
99   globals.forward_dll = arg;
100   globals.do_trace = 1;
101   globals.do_code = 1;
102 }
103
104 static void do_document (const char *arg)
105 {
106   globals.do_documentation = 1;
107 }
108
109 static void do_cdecl (const char *arg)
110 {
111   globals.do_cdecl = 1;
112 }
113
114
115 static void do_quiet (const char *arg)
116 {
117   globals.do_quiet = 1;
118 }
119
120
121 static void do_start (const char *arg)
122 {
123   globals.start_ordinal = atoi (arg);
124   if (!globals.start_ordinal)
125     fatal ("Invalid -s option (must be numeric)");
126 }
127
128
129 static void do_end (const char *arg)
130 {
131   globals.end_ordinal = atoi (arg);
132   if (!globals.end_ordinal)
133     fatal ("Invalid -e option (must be numeric)");
134 }
135
136
137 static void do_symfile (const char *arg)
138 {
139   FILE *f;
140   char symstring[256];    /* keep count with "%<width>s" below */
141   search_symbol *symbolp,**symbolptail = &globals.search_symbol;
142
143   if (!(f = fopen(arg, "rt")))
144     fatal ("Cannot open <symfile>");
145   while (1 == fscanf(f, "%255s", symstring))    /* keep count with [<width>] above */
146   {
147     symstring[sizeof(symstring)-1] = '\0';
148     if (!(symbolp = malloc(sizeof(*symbolp) + strlen(symstring))))
149       fatal ("Out of memory");
150     strcpy(symbolp->symbolname, symstring);
151     symbolp->found = 0;
152     symbolp->next = NULL;
153     *symbolptail = symbolp;
154     symbolptail = &symbolp->next;
155   }
156   if (fclose(f))
157     fatal ("Cannot close <symfile>");
158 }
159
160
161 static void do_verbose (const char *arg)
162 {
163   globals.do_verbose = 1;
164 }
165
166
167 static void do_symdmngl (const char *arg)
168 {
169     globals.do_demangle = 1;
170 }
171
172 static void do_dumphead (const char *arg)
173 {
174     globals.do_dumpheader = 1;
175 }
176
177 static void do_dumpsect (const char* arg)
178 {
179     globals.dumpsect = arg;
180 }
181
182 static void do_rawdebug (const char *arg)
183 {
184     globals.do_debug = 1;
185 }
186
187 static void do_dumpall(const char *arg)
188 {
189     globals.do_dumpheader = 1;
190     globals.do_dump_rawdata = 1;
191     globals.do_symbol_table = 1;
192     globals.dumpsect = "ALL";
193 }
194
195 static void do_symtable(const char* arg)
196 {
197     globals.do_symbol_table = 1;
198 }
199
200 struct my_option
201 {
202   const char *name;
203   Mode mode;
204   int   has_arg;
205   void  (*func)(const char *arg);
206   const char *usage;
207 };
208
209 static const struct my_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 <file>  Dumps the contents of a file (dll, exe, lib...)"},
228   {"-C",    DUMP, 0, do_symdmngl, "-C           Turns on symbol demangling"},
229   {"-f",    DUMP, 0, do_dumphead, "-f           Dumps file header information"},
230   {"-G",    DUMP, 0, do_rawdebug, "-G           Dumps raw debug information"},
231   {"-j",    DUMP, 1, do_dumpsect, "-j sect_name Dumps only the content of section sect_name (import, export, debug, resource, tls, clr)"},
232   {"-t",    DUMP, 0, do_symtable, "-t           Dumps symbol table"},
233   {"-x",    DUMP, 0, do_dumpall,  "-x           Dumps everything"},
234   {NULL,    NONE, 0, NULL,        NULL}
235 };
236
237 void do_usage (const char *arg)
238 {
239     const struct my_option *opt;
240     printf ("Usage: winedump [-h | sym <sym> | spec <dll> | dump <file>]\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
259     puts ("");
260     exit (1);
261 }
262
263
264 /*******************************************************************
265  *          parse_options
266  *
267  * Parse options from the argv array
268  */
269 static void parse_options (char *argv[])
270 {
271   const struct my_option *opt;
272   char *const *ptr;
273   const char *arg = NULL;
274
275   ptr = argv + 1;
276
277   while (*ptr != NULL)
278   {
279     for (opt = option_table; opt->name; opt++)
280     {
281      if (globals.mode != NONE && opt->mode != NONE && globals.mode != opt->mode)
282        continue;
283      if (((opt->has_arg == 1) && !strncmp (*ptr, opt->name, strlen (opt->name))) ||
284          ((opt->has_arg == 2) && !strcmp (*ptr, opt->name)))
285       {
286         arg = *ptr + strlen (opt->name);
287         if (*arg == '\0') arg = *++ptr;
288         break;
289       }
290       if (!strcmp (*ptr, opt->name))
291       {
292         arg = NULL;
293         break;
294       }
295     }
296
297     if (!opt->name)
298     {
299         if ((*ptr)[0] == '-')
300             fatal ("Unrecognized option");
301         if (globals.input_name != NULL)
302             fatal ("Only one file can be treated at once");
303         globals.input_name = *ptr;
304     }
305     else if (opt->has_arg && arg != NULL)
306         opt->func (arg);
307     else
308         opt->func ("");
309
310     ptr++;
311   }
312
313   if (globals.mode == SPEC && globals.do_code && !globals.directory)
314     fatal ("-I must be used if generating code");
315
316   if (VERBOSE && QUIET)
317     fatal ("Options -v and -q are mutually exclusive");
318
319   if (globals.mode == NONE)
320       do_dump("");
321 }
322
323 static void set_module_name(unsigned setUC)
324 {
325     const char* ptr;
326     char*       buf;
327     int         len;
328
329     /* FIXME: we shouldn't assume all module extensions are .dll in winedump
330      * in some cases, we could have some .drv for example
331      */
332     /* get module name from name */
333     if ((ptr = strrchr (globals.input_name, '/')))
334         ptr++;
335     else
336         ptr = globals.input_name;
337     len = strlen(ptr);
338     if (len > 4 && strcmp(ptr + len - 4, ".dll") == 0)
339         len -= 4;
340     buf = malloc(len + 1);
341     memcpy(buf, (const void*)ptr, len);
342     buf[len] = 0;
343     globals.input_module = buf;
344     OUTPUT_UC_DLL_NAME = (setUC) ? str_toupper( strdup (OUTPUT_DLL_NAME)) : "";
345 }
346
347 /* Marks the symbol as 'found'! */
348 /* return: perform-search */
349 static int symbol_searched(int count, const char *symbolname)
350 {
351     search_symbol *search_symbol;
352
353     if (!(count >= globals.start_ordinal
354           && (!globals.end_ordinal || count <= globals.end_ordinal)))
355         return 0;
356     if (!globals.search_symbol)
357         return 1;
358     for (search_symbol = globals.search_symbol;
359          search_symbol;
360          search_symbol = search_symbol->next)
361     {
362         if (!strcmp(symbolname, search_symbol->symbolname))
363         {
364             search_symbol->found = 1;
365             return 1;
366         }
367     }
368     return 0;
369 }
370
371 /* return: some symbols weren't found */
372 static int symbol_finish(void)
373 {
374     const search_symbol *search_symbol;
375     int started = 0;
376
377     for (search_symbol = globals.search_symbol;
378          search_symbol;
379          search_symbol = search_symbol->next)
380     {
381         if (search_symbol->found)
382             continue;
383         if (!started)
384         {
385             /* stderr? not a practice here */
386             puts("These requested <symfile> symbols weren't found:");
387             started = 1;
388         }
389         printf("\t%s\n",search_symbol->symbolname);
390     }
391     return started;
392 }
393
394 /*******************************************************************
395  *         main
396  */
397 #ifdef __GNUC__
398 int   main (int argc __attribute__((unused)), char *argv[])
399 #else
400 int   main (int argc, char *argv[])
401 #endif
402 {
403     parsed_symbol symbol;
404     int count = 0;
405
406     globals.mode = NONE;
407     globals.forward_dll = NULL;
408     globals.input_name = NULL;
409     globals.dumpsect = NULL;
410
411     parse_options (argv);
412
413     memset (&symbol, 0, sizeof (parsed_symbol));
414
415     switch (globals.mode)
416     {
417     case DMGL:
418         VERBOSE = 1;
419
420         if (globals.input_name == NULL)
421             fatal("No symbol name has been given\n");
422         printf("%s\n", get_symbol_str(globals.input_name));
423         break;
424
425     case SPEC:
426         if (globals.input_name == NULL)
427             fatal("No file name has been given\n");
428         set_module_name(1);
429         if (!dll_open (globals.input_name))
430             break;
431
432         output_spec_preamble ();
433         output_header_preamble ();
434         output_c_preamble ();
435
436         while (!dll_next_symbol (&symbol))
437         {
438             count++;
439
440             if (NORMAL)
441                 printf ("Export %3d - '%s' ...%c", count, symbol.symbol,
442                         VERBOSE ? '\n' : ' ');
443
444             if (globals.do_code && symbol_searched(count, symbol.symbol))
445             {
446                 /* Attempt to get information about the symbol */
447                 int result = symbol_demangle (&symbol);
448
449                 if (result)
450                     result = symbol_search (&symbol);
451
452                 if (!result && symbol.function_name)
453                     /* Clean up the prototype */
454                     symbol_clean_string (symbol.function_name);
455
456                 if (NORMAL)
457                     puts (result ? "[Not Found]" : "[OK]");
458             }
459             else if (NORMAL)
460                 puts ("[Ignoring]");
461
462             output_spec_symbol (&symbol);
463             output_header_symbol (&symbol);
464             output_c_symbol (&symbol);
465
466             symbol_clear (&symbol);
467         }
468
469         output_makefile ();
470
471         if (VERBOSE)
472             puts ("Finished, Cleaning up...");
473         if (symbol_finish())
474             return 1;
475         break;
476     case NONE:
477         do_usage(0);
478         break;
479     case DUMP:
480         if (globals.input_name == NULL)
481             fatal("No file name has been given\n");
482         set_module_name(0);
483         dump_file(globals.input_name);
484         break;
485     }
486
487     return 0;
488 }