]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Host/common/GetOptInc.cpp
Merge ^/head r314270 through r314419.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Host / common / GetOptInc.cpp
1 //===-- GetOptInc.cpp -------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "lldb/Host/common/GetOptInc.h"
11
12 #if defined(REPLACE_GETOPT) || defined(REPLACE_GETOPT_LONG) ||                 \
13     defined(REPLACE_GETOPT_LONG_ONLY)
14
15 // getopt.cpp
16 #include <errno.h>
17 #include <stdlib.h>
18 #include <string.h>
19
20 #if defined(REPLACE_GETOPT)
21 int opterr = 1;   /* if error message should be printed */
22 int optind = 1;   /* index into parent argv vector */
23 int optopt = '?'; /* character checked for validity */
24 int optreset;     /* reset getopt */
25 char *optarg;     /* argument associated with option */
26 #endif
27
28 #define PRINT_ERROR ((opterr) && (*options != ':'))
29
30 #define FLAG_PERMUTE 0x01  /* permute non-options to the end of argv */
31 #define FLAG_ALLARGS 0x02  /* treat non-options as args to option "-1" */
32 #define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
33
34 /* return values */
35 #define BADCH (int)'?'
36 #define BADARG ((*options == ':') ? (int)':' : (int)'?')
37 #define INORDER (int)1
38
39 #define EMSG ""
40
41 static int getopt_internal(int, char *const *, const char *,
42                            const struct option *, int *, int);
43 static int parse_long_options(char *const *, const char *,
44                               const struct option *, int *, int);
45 static int gcd(int, int);
46 static void permute_args(int, int, int, char *const *);
47
48 static const char *place = EMSG; /* option letter processing */
49
50 /* XXX: set optreset to 1 rather than these two */
51 static int nonopt_start = -1; /* first non option argument (for permute) */
52 static int nonopt_end = -1;   /* first option after non options (for permute) */
53
54 /*
55 * Compute the greatest common divisor of a and b.
56 */
57 static int gcd(int a, int b) {
58   int c;
59
60   c = a % b;
61   while (c != 0) {
62     a = b;
63     b = c;
64     c = a % b;
65   }
66
67   return (b);
68 }
69
70 static void pass() {}
71 #define warnx(a, ...) pass();
72
73 /*
74 * Exchange the block from nonopt_start to nonopt_end with the block
75 * from nonopt_end to opt_end (keeping the same order of arguments
76 * in each block).
77 */
78 static void permute_args(int panonopt_start, int panonopt_end, int opt_end,
79                          char *const *nargv) {
80   int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
81   char *swap;
82
83   /*
84   * compute lengths of blocks and number and size of cycles
85   */
86   nnonopts = panonopt_end - panonopt_start;
87   nopts = opt_end - panonopt_end;
88   ncycle = gcd(nnonopts, nopts);
89   cyclelen = (opt_end - panonopt_start) / ncycle;
90
91   for (i = 0; i < ncycle; i++) {
92     cstart = panonopt_end + i;
93     pos = cstart;
94     for (j = 0; j < cyclelen; j++) {
95       if (pos >= panonopt_end)
96         pos -= nnonopts;
97       else
98         pos += nopts;
99       swap = nargv[pos];
100       /* LINTED const cast */
101       ((char **)nargv)[pos] = nargv[cstart];
102       /* LINTED const cast */
103       ((char **)nargv)[cstart] = swap;
104     }
105   }
106 }
107
108 /*
109 * parse_long_options --
110 *  Parse long options in argc/argv argument vector.
111 * Returns -1 if short_too is set and the option does not match long_options.
112 */
113 static int parse_long_options(char *const *nargv, const char *options,
114                               const struct option *long_options, int *idx,
115                               int short_too) {
116   char *current_argv, *has_equal;
117   size_t current_argv_len;
118   int i, match;
119
120   current_argv = const_cast<char *>(place);
121   match = -1;
122
123   optind++;
124
125   if ((has_equal = strchr(current_argv, '=')) != NULL) {
126     /* argument found (--option=arg) */
127     current_argv_len = has_equal - current_argv;
128     has_equal++;
129   } else
130     current_argv_len = strlen(current_argv);
131
132   for (i = 0; long_options[i].name; i++) {
133     /* find matching long option */
134     if (strncmp(current_argv, long_options[i].name, current_argv_len))
135       continue;
136
137     if (strlen(long_options[i].name) == current_argv_len) {
138       /* exact match */
139       match = i;
140       break;
141     }
142     /*
143     * If this is a known short option, don't allow
144     * a partial match of a single character.
145     */
146     if (short_too && current_argv_len == 1)
147       continue;
148
149     if (match == -1) /* partial match */
150       match = i;
151     else {
152       /* ambiguous abbreviation */
153       if (PRINT_ERROR)
154         warnx(ambig, (int)current_argv_len, current_argv);
155       optopt = 0;
156       return (BADCH);
157     }
158   }
159   if (match != -1) { /* option found */
160     if (long_options[match].has_arg == no_argument && has_equal) {
161       if (PRINT_ERROR)
162         warnx(noarg, (int)current_argv_len, current_argv);
163       /*
164       * XXX: GNU sets optopt to val regardless of flag
165       */
166       if (long_options[match].flag == NULL)
167         optopt = long_options[match].val;
168       else
169         optopt = 0;
170       return (BADARG);
171     }
172     if (long_options[match].has_arg == required_argument ||
173         long_options[match].has_arg == optional_argument) {
174       if (has_equal)
175         optarg = has_equal;
176       else if (long_options[match].has_arg == required_argument) {
177         /*
178         * optional argument doesn't use next nargv
179         */
180         optarg = nargv[optind++];
181       }
182     }
183     if ((long_options[match].has_arg == required_argument) &&
184         (optarg == NULL)) {
185       /*
186       * Missing argument; leading ':' indicates no error
187       * should be generated.
188       */
189       if (PRINT_ERROR)
190         warnx(recargstring, current_argv);
191       /*
192       * XXX: GNU sets optopt to val regardless of flag
193       */
194       if (long_options[match].flag == NULL)
195         optopt = long_options[match].val;
196       else
197         optopt = 0;
198       --optind;
199       return (BADARG);
200     }
201   } else { /* unknown option */
202     if (short_too) {
203       --optind;
204       return (-1);
205     }
206     if (PRINT_ERROR)
207       warnx(illoptstring, current_argv);
208     optopt = 0;
209     return (BADCH);
210   }
211   if (idx)
212     *idx = match;
213   if (long_options[match].flag) {
214     *long_options[match].flag = long_options[match].val;
215     return (0);
216   } else
217     return (long_options[match].val);
218 }
219
220 /*
221 * getopt_internal --
222 *  Parse argc/argv argument vector.  Called by user level routines.
223 */
224 static int getopt_internal(int nargc, char *const *nargv, const char *options,
225                            const struct option *long_options, int *idx,
226                            int flags) {
227   const char *oli; /* option letter list index */
228   int optchar, short_too;
229   static int posixly_correct = -1;
230
231   if (options == NULL)
232     return (-1);
233
234   /*
235   * XXX Some GNU programs (like cvs) set optind to 0 instead of
236   * XXX using optreset.  Work around this braindamage.
237   */
238   if (optind == 0)
239     optind = optreset = 1;
240
241   /*
242   * Disable GNU extensions if POSIXLY_CORRECT is set or options
243   * string begins with a '+'.
244   */
245   if (posixly_correct == -1 || optreset)
246     posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
247   if (*options == '-')
248     flags |= FLAG_ALLARGS;
249   else if (posixly_correct || *options == '+')
250     flags &= ~FLAG_PERMUTE;
251   if (*options == '+' || *options == '-')
252     options++;
253
254   optarg = NULL;
255   if (optreset)
256     nonopt_start = nonopt_end = -1;
257 start:
258   if (optreset || !*place) { /* update scanning pointer */
259     optreset = 0;
260     if (optind >= nargc) { /* end of argument vector */
261       place = EMSG;
262       if (nonopt_end != -1) {
263         /* do permutation, if we have to */
264         permute_args(nonopt_start, nonopt_end, optind, nargv);
265         optind -= nonopt_end - nonopt_start;
266       } else if (nonopt_start != -1) {
267         /*
268         * If we skipped non-options, set optind
269         * to the first of them.
270         */
271         optind = nonopt_start;
272       }
273       nonopt_start = nonopt_end = -1;
274       return (-1);
275     }
276     if (*(place = nargv[optind]) != '-' ||
277         (place[1] == '\0' && strchr(options, '-') == NULL)) {
278       place = EMSG; /* found non-option */
279       if (flags & FLAG_ALLARGS) {
280         /*
281         * GNU extension:
282         * return non-option as argument to option 1
283         */
284         optarg = nargv[optind++];
285         return (INORDER);
286       }
287       if (!(flags & FLAG_PERMUTE)) {
288         /*
289         * If no permutation wanted, stop parsing
290         * at first non-option.
291         */
292         return (-1);
293       }
294       /* do permutation */
295       if (nonopt_start == -1)
296         nonopt_start = optind;
297       else if (nonopt_end != -1) {
298         permute_args(nonopt_start, nonopt_end, optind, nargv);
299         nonopt_start = optind - (nonopt_end - nonopt_start);
300         nonopt_end = -1;
301       }
302       optind++;
303       /* process next argument */
304       goto start;
305     }
306     if (nonopt_start != -1 && nonopt_end == -1)
307       nonopt_end = optind;
308
309     /*
310     * If we have "-" do nothing, if "--" we are done.
311     */
312     if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
313       optind++;
314       place = EMSG;
315       /*
316       * We found an option (--), so if we skipped
317       * non-options, we have to permute.
318       */
319       if (nonopt_end != -1) {
320         permute_args(nonopt_start, nonopt_end, optind, nargv);
321         optind -= nonopt_end - nonopt_start;
322       }
323       nonopt_start = nonopt_end = -1;
324       return (-1);
325     }
326   }
327
328   /*
329   * Check long options if:
330   *  1) we were passed some
331   *  2) the arg is not just "-"
332   *  3) either the arg starts with -- we are getopt_long_only()
333   */
334   if (long_options != NULL && place != nargv[optind] &&
335       (*place == '-' || (flags & FLAG_LONGONLY))) {
336     short_too = 0;
337     if (*place == '-')
338       place++; /* --foo long option */
339     else if (*place != ':' && strchr(options, *place) != NULL)
340       short_too = 1; /* could be short option too */
341
342     optchar = parse_long_options(nargv, options, long_options, idx, short_too);
343     if (optchar != -1) {
344       place = EMSG;
345       return (optchar);
346     }
347   }
348
349   if ((optchar = (int)*place++) == (int)':' ||
350       (optchar == (int)'-' && *place != '\0') ||
351       (oli = strchr(options, optchar)) == NULL) {
352     /*
353     * If the user specified "-" and  '-' isn't listed in
354     * options, return -1 (non-option) as per POSIX.
355     * Otherwise, it is an unknown option character (or ':').
356     */
357     if (optchar == (int)'-' && *place == '\0')
358       return (-1);
359     if (!*place)
360       ++optind;
361     if (PRINT_ERROR)
362       warnx(illoptchar, optchar);
363     optopt = optchar;
364     return (BADCH);
365   }
366   if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
367     /* -W long-option */
368     if (*place) /* no space */
369       /* NOTHING */;
370     else if (++optind >= nargc) { /* no arg */
371       place = EMSG;
372       if (PRINT_ERROR)
373         warnx(recargchar, optchar);
374       optopt = optchar;
375       return (BADARG);
376     } else /* white space */
377       place = nargv[optind];
378     optchar = parse_long_options(nargv, options, long_options, idx, 0);
379     place = EMSG;
380     return (optchar);
381   }
382   if (*++oli != ':') { /* doesn't take argument */
383     if (!*place)
384       ++optind;
385   } else { /* takes (optional) argument */
386     optarg = NULL;
387     if (*place) /* no white space */
388       optarg = const_cast<char *>(place);
389     else if (oli[1] != ':') {  /* arg not optional */
390       if (++optind >= nargc) { /* no arg */
391         place = EMSG;
392         if (PRINT_ERROR)
393           warnx(recargchar, optchar);
394         optopt = optchar;
395         return (BADARG);
396       } else
397         optarg = nargv[optind];
398     }
399     place = EMSG;
400     ++optind;
401   }
402   /* dump back option letter */
403   return (optchar);
404 }
405
406 /*
407 * getopt --
408 *  Parse argc/argv argument vector.
409 *
410 * [eventually this will replace the BSD getopt]
411 */
412 #if defined(REPLACE_GETOPT)
413 int getopt(int nargc, char *const *nargv, const char *options) {
414
415   /*
416   * We don't pass FLAG_PERMUTE to getopt_internal() since
417   * the BSD getopt(3) (unlike GNU) has never done this.
418   *
419   * Furthermore, since many privileged programs call getopt()
420   * before dropping privileges it makes sense to keep things
421   * as simple (and bug-free) as possible.
422   */
423   return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
424 }
425 #endif
426
427 /*
428 * getopt_long --
429 *  Parse argc/argv argument vector.
430 */
431 #if defined(REPLACE_GETOPT_LONG)
432 int getopt_long(int nargc, char *const *nargv, const char *options,
433                 const struct option *long_options, int *idx) {
434   return (
435       getopt_internal(nargc, nargv, options, long_options, idx, FLAG_PERMUTE));
436 }
437 #endif
438
439 /*
440 * getopt_long_only --
441 *  Parse argc/argv argument vector.
442 */
443 #if defined(REPLACE_GETOPT_LONG_ONLY)
444 int getopt_long_only(int nargc, char *const *nargv, const char *options,
445                      const struct option *long_options, int *idx) {
446
447   return (getopt_internal(nargc, nargv, options, long_options, idx,
448                           FLAG_PERMUTE | FLAG_LONGONLY));
449 }
450 #endif
451
452 #endif