summaryrefslogtreecommitdiffstats
path: root/tools/apriori/cmdline.c
blob: 95f112a889235202920b2ff3eed3145b821633ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#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;
}