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