shell32/tests: Fix a copy and paste error (PVS-Studio).
[wine/multimedia.git] / tools / winedump / main.c
blobdfd15b071544d7aaf508448c46f33b3e291bad1c
1 /*
2 * Option processing and main()
4 * Copyright 2000 Jon Griffiths
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.
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.
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include "winedump.h"
26 _globals globals; /* All global variables */
29 static void do_include (const char *arg)
31 char *newIncludes;
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;
40 globals.do_code = TRUE;
44 static inline const char* strip_ext (const char *str)
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);
54 static void do_name (const char *arg)
56 globals.dll_name = strip_ext (arg);
60 static void do_spec (const char *arg)
62 if (globals.mode != NONE) fatal("Only one mode can be specified\n");
63 globals.mode = SPEC;
67 static void do_demangle (const char *arg)
69 if (globals.mode != NONE) fatal("Only one mode can be specified\n");
70 globals.mode = DMGL;
71 globals.do_code = TRUE;
72 globals.do_demangle = TRUE;
76 static void do_dump (const char *arg)
78 if (globals.mode != NONE) fatal("Only one mode can be specified\n");
79 globals.mode = DUMP;
80 globals.do_code = TRUE;
84 static void do_code (const char *arg)
86 globals.do_code = TRUE;
90 static void do_trace (const char *arg)
92 globals.do_trace = TRUE;
93 globals.do_code = TRUE;
97 static void do_forward (const char *arg)
99 globals.forward_dll = arg;
100 globals.do_trace = TRUE;
101 globals.do_code = TRUE;
104 static void do_document (const char *arg)
106 globals.do_documentation = TRUE;
109 static void do_cdecl (const char *arg)
111 globals.do_cdecl = TRUE;
115 static void do_quiet (const char *arg)
117 globals.do_quiet = TRUE;
121 static void do_start (const char *arg)
123 globals.start_ordinal = atoi (arg);
124 if (!globals.start_ordinal)
125 fatal ("Invalid -s option (must be numeric)");
129 static void do_end (const char *arg)
131 globals.end_ordinal = atoi (arg);
132 if (!globals.end_ordinal)
133 fatal ("Invalid -e option (must be numeric)");
137 static void do_symfile (const char *arg)
139 FILE *f;
140 char symstring[256]; /* keep count with "%<width>s" below */
141 search_symbol *symbolp,**symbolptail = &globals.search_symbol;
143 if (!(f = fopen(arg, "rt")))
144 fatal ("Cannot open <symfile>");
145 while (1 == fscanf(f, "%255s", symstring)) /* keep count with [<width>] above */
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 = FALSE;
152 symbolp->next = NULL;
153 *symbolptail = symbolp;
154 symbolptail = &symbolp->next;
156 if (fclose(f))
157 fatal ("Cannot close <symfile>");
161 static void do_verbose (const char *arg)
163 globals.do_verbose = TRUE;
167 static void do_symdmngl (const char *arg)
169 globals.do_demangle = TRUE;
172 static void do_dumphead (const char *arg)
174 globals.do_dumpheader = TRUE;
177 static void do_dumpsect (const char* arg)
179 globals.dumpsect = arg;
182 static void do_rawdebug (const char *arg)
184 globals.do_debug = TRUE;
187 static void do_dumpall(const char *arg)
189 globals.do_dumpheader = TRUE;
190 globals.do_dump_rawdata = TRUE;
191 globals.do_symbol_table = TRUE;
192 globals.dumpsect = "ALL";
195 static void do_symtable(const char* arg)
197 globals.do_symbol_table = TRUE;
200 struct my_option
202 const char *name;
203 Mode mode;
204 int has_arg;
205 void (*func)(const char *arg);
206 const char *usage;
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> Dump the contents of 'file' (dll, exe, lib...)"},
228 {"-C", DUMP, 0, do_symdmngl, "-C Turn on symbol demangling"},
229 {"-f", DUMP, 0, do_dumphead, "-f Dump file header information"},
230 {"-G", DUMP, 0, do_rawdebug, "-G Dump raw debug information"},
231 {"-j", DUMP, 1, do_dumpsect, "-j <sect_name> Dump only the content of section 'sect_name' (import, export, debug, resource, tls, clr, reloc, except)"},
232 {"-t", DUMP, 0, do_symtable, "-t Dump symbol table"},
233 {"-x", DUMP, 0, do_dumpall, "-x Dump everything"},
234 {NULL, NONE, 0, NULL, NULL}
237 void do_usage (const char *arg)
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);
259 puts ("");
260 exit (1);
264 /*******************************************************************
265 * parse_options
267 * Parse options from the argv array
269 static void parse_options (char *argv[])
271 const struct my_option *opt;
272 char *const *ptr;
273 const char *arg = NULL;
275 ptr = argv + 1;
277 while (*ptr != NULL)
279 for (opt = option_table; opt->name; opt++)
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)))
286 arg = *ptr + strlen (opt->name);
287 if (*arg == '\0') arg = *++ptr;
288 break;
290 if (!strcmp (*ptr, opt->name))
292 arg = NULL;
293 break;
297 if (!opt->name)
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;
305 else if (opt->has_arg && arg != NULL)
306 opt->func (arg);
307 else
308 opt->func ("");
310 ptr++;
313 if (globals.mode == SPEC && globals.do_code && !globals.directory)
314 fatal ("-I must be used if generating code");
316 if (VERBOSE && QUIET)
317 fatal ("Options -v and -q are mutually exclusive");
319 if (globals.mode == NONE)
320 do_dump("");
323 static void set_module_name(BOOL setUC)
325 const char* ptr;
326 char* buf;
327 int len;
329 /* FIXME: we shouldn't assume all module extensions are .dll in winedump
330 * in some cases, we could have some .drv for example
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)) : "";
347 /* Marks the symbol as 'found'! */
348 /* return: perform-search */
349 static BOOL symbol_searched(int count, const char *symbolname)
351 search_symbol *search_symbol;
353 if (!(count >= globals.start_ordinal
354 && (!globals.end_ordinal || count <= globals.end_ordinal)))
355 return FALSE;
356 if (!globals.search_symbol)
357 return TRUE;
358 for (search_symbol = globals.search_symbol;
359 search_symbol;
360 search_symbol = search_symbol->next)
362 if (!strcmp(symbolname, search_symbol->symbolname))
364 search_symbol->found = TRUE;
365 return TRUE;
368 return FALSE;
371 /* return: some symbols weren't found */
372 static BOOL symbol_finish(void)
374 const search_symbol *search_symbol;
375 BOOL started = FALSE;
377 for (search_symbol = globals.search_symbol;
378 search_symbol;
379 search_symbol = search_symbol->next)
381 if (search_symbol->found)
382 continue;
383 if (!started)
385 /* stderr? not a practice here */
386 puts("These requested <symfile> symbols weren't found:");
387 started = TRUE;
389 printf("\t%s\n",search_symbol->symbolname);
391 return started;
394 /*******************************************************************
395 * main
397 #ifdef __GNUC__
398 int main (int argc __attribute__((unused)), char *argv[])
399 #else
400 int main (int argc, char *argv[])
401 #endif
403 parsed_symbol symbol;
404 int count = 0;
406 globals.mode = NONE;
407 globals.forward_dll = NULL;
408 globals.input_name = NULL;
409 globals.dumpsect = NULL;
411 parse_options (argv);
413 memset (&symbol, 0, sizeof (parsed_symbol));
415 switch (globals.mode)
417 case DMGL:
418 VERBOSE = TRUE;
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;
425 case SPEC:
426 if (globals.input_name == NULL)
427 fatal("No file name has been given\n");
428 set_module_name(TRUE);
429 if (!dll_open (globals.input_name))
430 break;
432 output_spec_preamble ();
433 output_header_preamble ();
434 output_c_preamble ();
436 while (dll_next_symbol (&symbol))
438 count++;
440 if (NORMAL)
441 printf ("Export %3d - '%s' ...%c", count, symbol.symbol,
442 VERBOSE ? '\n' : ' ');
444 if (globals.do_code && symbol_searched(count, symbol.symbol))
446 /* Attempt to get information about the symbol */
447 BOOL result = symbol_demangle (&symbol) || symbol_search(&symbol);
449 if (result && symbol.function_name)
450 /* Clean up the prototype */
451 symbol_clean_string (symbol.function_name);
453 if (NORMAL)
454 puts (result ? "[OK]" : "[Not Found]");
456 else if (NORMAL)
457 puts ("[Ignoring]");
459 output_spec_symbol (&symbol);
460 output_header_symbol (&symbol);
461 output_c_symbol (&symbol);
463 symbol_clear (&symbol);
466 output_makefile ();
468 if (VERBOSE)
469 puts ("Finished, Cleaning up...");
470 if (symbol_finish())
471 return 1;
472 break;
473 case NONE:
474 do_usage(0);
475 break;
476 case DUMP:
477 if (globals.input_name == NULL)
478 fatal("No file name has been given\n");
479 set_module_name(FALSE);
480 dump_file(globals.input_name);
481 break;
484 return 0;