1 /* Id */
2 /* $NetBSD: options.c,v 1.1.1.1 2016/02/09 20:29:13 plunky Exp $ */
3
4 /*-
5 * Copyright (c) 2014 Iain Hibbert.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25
26 #include <ctype.h>
27 #include <string.h>
28
29 #include "driver.h"
30
31 /*
32 * list of options we understand. The list should be sorted by
33 * initial char, then by increasing match
34 */
35 struct options {
36 const char * name;
37 unsigned int type;
38 void (*func)(int, char *);
39 void * addr;
40 };
41
42 /* option types */
43 #define FLAG (0) /* match name exactly */
44 #define STR(n) ((n) & 0xff) /* match n chars (or all if n = 0) */
45 #define ARG(n) (STR(n)|VAL) /* match, and require an argument */
46 #define VAL 0x0100 /* arg value is required */
47
48 static void ignore(int, char *); /* do nothing */
49
50 static void opt_set(int, char *); /* set option */
51 static void opt_set2(int, char *); /* set option */
52 static void opt_clr(int, char *); /* clear option */
53 static void opt_add(int, char *); /* add option to list */
54
55 static void str_set(int, char *); /* set string option */
56 static void str_add(int, char *); /* add string to list */
57 static void str_expand(int, char *); /* expand string to list */
58
59 static void arg_add(int, char *); /* add option and argument to list */
60
61 static void str_Olevel(int, char *); /* handle -Olevel */
62 static void str_glevel(int, char *); /* handle -glevel */
63
64 static struct options options[] = {
65 { "-param", ARG(0), ignore, NULL },
66 { "-sysroot=", STR(9), str_set, &opt.sysroot },
67 { "-version", FLAG, opt_set, &opt.version, },
68 { "B", ARG(1), arg_add, &opt.prefix },
69 { "C", FLAG, opt_set, &opt.C },
70 { "CC", FLAG, opt_set2, &opt.C },
71 { "D", ARG(1), arg_add, &opt.DIU },
72 { "E", FLAG, opt_set, &opt.E },
73 { "I", ARG(1), arg_add, &opt.DIU },
74 { "L", ARG(1), arg_add, &opt.ldargs },
75 { "M", FLAG, opt_set, &opt.M },
76 { "O", STR(1), str_Olevel, NULL },
77 { "P", FLAG, opt_set, &opt.P },
78 { "S", FLAG, opt_set, &opt.S },
79 { "U", ARG(1), arg_add, &opt.DIU },
80 { "Wa,", STR(3), str_expand, &opt.Wa },
81 { "Wl,", STR(3), str_expand, &opt.Wl },
82 { "Wp,", STR(3), str_expand, &opt.Wp },
83 { "W", STR(1), str_Wflag, NULL }, // XX
84 { "X", FLAG, opt_set, &opt.savetemps },
85 { "c", FLAG, opt_set, &opt.c },
86 { "compatibility-version", FLAG, ignore, NULL },
87 { "current-version", FLAG, ignore, NULL },
88 { "dynamiclib", FLAG, opt_set, &opt.dynamiclib },
89 { "ffreestanding", FLAG, opt_clr, &opt.hosted },
90 { "fno-freestanding", FLAG, opt_set, &opt.hosted },
91 { "fsigned-char", FLAG, opt_clr, &opt.uchar },
92 { "fno-signed-char", FLAG, opt_set, &opt.uchar },
93 { "funsigned-char", FLAG, opt_set, &opt.uchar },
94 { "fno-unsigned-char", FLAG, opt_clr, &opt.uchar },
95 { "fpic", FLAG, opt_set, &opt.pic },
96 { "fno-pic", FLAG, opt_clr, &opt.pic },
97 { "fPIC", FLAG, opt_set, &opt.pic },
98 { "fno-PIC", FLAG, opt_clr, &opt.pic },
99 { "fstack-protector", FLAG, opt_set, &opt.ssp },
100 { "fno-stack-protector", FLAG, opt_clr, &opt.ssp },
101 { "fstack-protector-all", FLAG, opt_set, &opt.ssp },
102 { "fno-stack-protector-all",FLAG, opt_clr, &opt.ssp },
103 { "f", STR(1), ignore, NULL },
104 { "g", STR(1), str_glevel, NULL },
105 { "idirafter", FLAG, opt_set, &opt.idirafter },
106 { "isystem", ARG(0), str_set, &opt.isystem },
107 { "include", ARG(0), str_add, &opt.include },
108 { "install-name", ARG(0), ignore, NULL }, // XX
109 { "iquote", ARG(0), ignore, NULL }, // XX
110 { "isysroot", ARG(0), str_set, &opt.isysroot },
111 { "i", STR(1), opt_add, &opt.ldargs },
112 { "k", FLAG, opt_set, &opt.pic },
113 { "l", ARG(1), arg_add, &opt.ldargs },
114 #ifdef mach_arm
115 { "mbig-endian", FLAG, opt_set, &opt.bigendian },
116 { "mlittle-endian", FLAG, opt_clr, &opt.bigendian },
117 #endif
118 #ifdef mach_amd64 || mach_i386
119 { "m32", FLAG, opt_set, &opt.m32 },
120 { "m64", FLAG, opt_clr, &opt.m32 },
121 #endif
122 { "m", ARG(1), ignore, NULL }, // XX
123 { "nostdinc", FLAG, opt_clr, &opt.stdinc },
124 { "nostdinc++", FLAG, opt_clr, &opt.cxxinc },
125 { "nostdlib", FLAG, opt_clr, &opt.stdlib },
126 { "nostartfiles", FLAG, opt_clr, &opt.startfiles },
127 { "nodefaultlibs", FLAG, opt_clr, &opt.defaultlibs},
128 { "n", STR(1), arg_add, &opt.ldargs }, // XX
129 { "o", ARG(1), str_set, &opt.outfile },
130 { "pedantic", FLAG, opt_set, &opt.pedantic },
131 { "p", FLAG, opt_set, &opt.profile },
132 { "pg", FLAG, opt_set, &opt.profile },
133 { "pipe", FLAG, opt_set, &opt.pipe },
134 { "print-prog-name=", STR(15), ignore, NULL }, // XX
135 { "print-multi-os-directory", FLAG, opt_set, &opt.print },
136 { "pthread", FLAG, opt_set, &opt.pthread },
137 { "r", FLAG, opt_set, &opt.r },
138 { "save-temps", FLAG, opt_set, &opt.savetemps },
139 { "shared", FLAG, opt_set, &opt.shared },
140 { "static", FLAG, opt_set, &opt.ldstatic },
141 { "symbolic", FLAG, opt_set, &opt.symbolic },
142 { "std=", STR(4), str_standard, NULL }, // XX
143 { "t", FLAG, opt_set, &opt.traditional},
144 { "traditional", FLAG, opt_set, &opt.traditional},
145 { "undef", FLAG, opt_clr, &opt.stddef },
146 { "v", FLAG, opt_set, &opt.verbose },
147 { "x", ARG(1), arg_language, NULL }, // XX
148 };
149
150 /* do nothing */
151 static void
ignore(int n,char * arg)152 ignore(int n, char *arg)
153 {
154 fprintf(stderr, "option `-%s' ignored\n", options[n].name);
155 }
156
157 /* set option */
158 static void
opt_set(int n,char * arg)159 opt_set(int n, char *arg)
160 {
161
162 *(int *)(options[n].addr) = 1;
163 }
164
165 /* set option=2 */
166 static void
opt_set2(int n,char * arg)167 opt_set2(int n, char *arg)
168 {
169
170 *(int *)(options[n].addr) = 2;
171 }
172
173 /* clear option */
174 static void
opt_clr(int n,char * arg)175 opt_clr(int n, char *arg)
176 {
177
178 *(int *)(options[n].addr) = 0;
179 }
180
181 /* add option to list */
182 static void
opt_add(int n,char * arg)183 opt_add(int n, char *arg)
184 {
185 list_t *l = options[n].addr;
186
187 list_add(l, "-%s", options[n].name);
188 }
189
190 /* set string option */
191 static void
str_set(int n,char * arg)192 str_set(int n, char *arg)
193 {
194 char **p = options[n].addr;
195
196 if (*p != NULL)
197 warning("option `-%s' was already set", options[n].name);
198
199 *p = arg;
200 }
201
202 /* add string to list */
203 static void
str_add(int n,char * arg)204 str_add(int n, char *arg)
205 {
206 list_t *l = options[n].addr;
207
208 list_add(l, arg);
209 }
210
211 /* expand comma separated string to list */
212 static void
str_expand(int n,char * arg)213 str_expand(int n, char *arg)
214 {
215 list_t *l = options[n].addr;
216 char *next;
217
218 while (arg != NULL) {
219 next = strchr(arg, ',');
220 if (next != NULL)
221 *next++ = '\0';
222
223 list_add(l, arg);
224 arg = next;
225 }
226 }
227
228 /* add option and argument to list */
229 static void
arg_add(int n,char * arg)230 arg_add(int n, char *arg)
231 {
232 list_t *l = options[n].addr;
233
234 list_add(l, "-%s", options[n].name);
235 list_add(l, arg);
236 }
237
238 /* handle -Olevel */
239 static void
str_Olevel(int n,char * arg)240 str_Olevel(int n, char *arg)
241 {
242
243 if (arg[0] == '\0')
244 opt.optim++;
245 else if (arg[1] == '\0' && isdigit((unsigned char)arg[1]))
246 opt.optim = arg[1] - '0';
247 else if (arg[1] == '\0' && arg[1] == 's')
248 opt.optim = 1; /* optimize for space only */
249 else
250 warning("unknown optimization `-O%s'", arg);
251 }
252
253 /* handle -glevel */
254 static void
str_glevel(int n,char * arg)255 str_glevel(int n, char *arg)
256 {
257
258 if (arg[0] == '\0')
259 opt.debug++;
260 else if (arg[1] == '\0' && isdigit((unsigned char)arg[1]))
261 opt.debug = arg[1] - '0';
262 else
263 warning("unknown debug `-g%s'", arg);
264 }
265
266 /*
267 * return true if av1 is used
268 */
269 bool
add_option(char * av0,char * av1)270 add_option(char *av0, char *av1)
271 {
272 unsigned int n;
273 char *p;
274 size_t i
275
276 i = 0;
277 p = av0 + 1; /* skip initial `-' */
278
279 while (i < ARRAYLEN(options) && *p != options[i].name[0])
280 i++;
281
282 while (i < ARRAYLEN(options) && *p == options[i].name[0]) {
283 n = STR(options[i].type);
284 if ((n > 0 && strncmp(options[i].name, p, n) == 0)
285 || (n == 0 && strcmp(options[i].name, p) == 0)) {
286 if ((options[i].type & VAL)
287 && (n == 0 || *(p += n) == '\0')
288 && (p = av1) == NULL) {
289 warning("option `%s' requires a value", av0);
290 return false;
291 }
292
293 options[i].func(i, p);
294 return (p == av1);
295 }
296 i++;
297 }
298
299 warning("unknown option `%s'", av0);
300 return false;
301 }
302