#include <debug.h> #include <cmdline.h> #include <stdio.h> #include <stdlib.h> #include <getopt.h> #include <string.h> #include <ctype.h> extern char *optarg; extern int optind, opterr, optopt; static struct option long_options[] = { {"start-address", required_argument, 0, 's'}, {"inc-address", required_argument, 0, 'i'}, {"locals-only", no_argument, 0, 'l'}, {"quiet", no_argument, 0, 'Q'}, {"noupdate", no_argument, 0, 'n'}, {"lookup", required_argument, 0, 'L'}, {"default", required_argument, 0, 'D'}, {"verbose", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {"mapfile", required_argument, 0, 'M'}, {"output", required_argument, 0, 'o'}, {"prelinkmap", required_argument, 0, 'p'}, {0, 0, 0, 0}, }; /* This array must parallel long_options[] */ static const char *descriptions[] = { "start address to prelink libraries to", "address increment for each library", "prelink local relocations only", "suppress informational and non-fatal error messages", "do a dry run--calculate the prelink info but do not update any files", "provide a directory for library lookup", "provide a default library or executable for symbol lookup", "print verbose output", "print help screen", "print a list of prelink addresses to file (prefix filename with + to append instead of overwrite)", "specify an output directory (if multiple inputs) or file (is single input)", "specify a file with prelink addresses instead of a --start-address/--inc-address combination", }; void print_help(const char *name) { fprintf(stdout, "invokation:\n" "\t%s file1 [file2 file3 ...] -Ldir1 [-Ldir2 ...] -saddr -iinc [-Vqn] [-M<logfile>]\n" "\t%s -l file [-Vqn] [-M<logfile>]\n" "\t%s -h\n\n", name, name, name); fprintf(stdout, "options:\n"); struct option *opt = long_options; const char **desc = descriptions; while (opt->name) { fprintf(stdout, "\t-%c/--%s%s: %s\n", opt->val, opt->name, (opt->has_arg ? " (argument)" : ""), *desc); opt++; desc++; } } int get_options(int argc, char **argv, int *start_addr, int *inc_addr, int *locals_only, int *quiet, int *dry_run, char ***dirs, int *num_dirs, char ***defaults, int *num_defaults, int *verbose, char **mapfile, char **output, char **prelinkmap) { int c; ASSERT(dry_run); *dry_run = 0; ASSERT(quiet); *quiet = 0; ASSERT(verbose); *verbose = 0; ASSERT(dirs); *dirs = NULL; ASSERT(num_dirs); *num_dirs = 0; ASSERT(defaults); *defaults = NULL; ASSERT(num_defaults); *num_defaults = 0; ASSERT(start_addr); *start_addr = -1; ASSERT(inc_addr); *inc_addr = -1; ASSERT(locals_only); *locals_only = 0; ASSERT(mapfile); *mapfile = NULL; ASSERT(output); *output = NULL; ASSERT(prelinkmap); *prelinkmap = NULL; int dirs_size = 0; int defaults_size = 0; while (1) { /* getopt_long stores the option index here. */ int option_index = 0; c = getopt_long (argc, argv, "VhnQlL:D:s:i:M:o:p:", long_options, &option_index); /* Detect the end of the options. */ if (c == -1) break; if (isgraph(c)) { INFO ("option -%c with value `%s'\n", c, (optarg ?: "(null)")); } #define SET_STRING_OPTION(name) do { \ ASSERT(optarg); \ (*name) = strdup(optarg); \ } while(0) #define SET_REPEATED_STRING_OPTION(arr, num, size) do { \ if (*num == size) { \ size += 10; \ *arr = (char **)REALLOC(*arr, size * sizeof(char *)); \ } \ SET_STRING_OPTION(((*arr) + *num)); \ (*num)++; \ } while(0) #define SET_INT_OPTION(val) do { \ ASSERT(optarg); \ if (strlen(optarg) >= 2 && optarg[0] == '0' && optarg[1] == 'x') { \ FAILIF(1 != sscanf(optarg+2, "%x", val), \ "Expecting a hexadecimal argument!\n"); \ } else { \ FAILIF(1 != sscanf(optarg, "%d", val), \ "Expecting a decimal argument!\n"); \ } \ } while(0) switch (c) { case 0: /* If this option set a flag, do nothing else now. */ if (long_options[option_index].flag != 0) break; INFO ("option %s", long_options[option_index].name); if (optarg) INFO (" with arg %s", optarg); INFO ("\n"); break; case 'Q': *quiet = 1; break; case 'n': *dry_run = 1; break; case 'M': SET_STRING_OPTION(mapfile); break; case 'o': SET_STRING_OPTION(output); break; case 'p': SET_STRING_OPTION(prelinkmap); break; case 's': SET_INT_OPTION(start_addr); break; case 'i': SET_INT_OPTION(inc_addr); break; case 'L': SET_REPEATED_STRING_OPTION(dirs, num_dirs, dirs_size); break; case 'D': SET_REPEATED_STRING_OPTION(defaults, num_defaults, defaults_size); break; case 'l': *locals_only = 1; break; case 'h': print_help(argv[0]); exit(1); break; case 'V': *verbose = 1; break; case '?': /* getopt_long already printed an error message. */ break; #undef SET_STRING_OPTION #undef SET_REPEATED_STRING_OPTION #undef SET_INT_OPTION default: FAILIF(1, "Unknown option"); } } return optind; }