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