CUBRID Engine  latest
cubrid_getopt_long.c
Go to the documentation of this file.
1 /*-
2  * Copyright (c) 2000 The NetBSD Foundation, Inc.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to The NetBSD Foundation
6  * by Dieter Baron and Thomas Klausner.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in the
15  * documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <assert.h>
31 #include "config.h"
32 
33 #ifndef HAVE_GETOPT_LONG
34 #include <errno.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include "cubrid_getopt.h"
40 
41 #define REPLACE_GETOPT
42 
43 #ifndef _DIAGASSERT
44 #define _DIAGASSERT(e)
45 #endif
46 
47 #ifdef REPLACE_GETOPT
48 #ifdef __weak_alias
49 __weak_alias (getopt, _getopt)
50 #endif
51  int opterr = 1; /* if error message should be printed */
52  int optind = 1; /* index into parent argv vector */
53  int optopt = '?'; /* character checked for validity */
54  int optreset; /* reset getopt */
55  char *optarg = NULL; /* argument associated with option */
56 #endif
57 
58 #ifdef __weak_alias
59 __weak_alias (getopt_long, _getopt_long)
60 #endif
61 #define IGNORE_FIRST (*options == '-' || *options == '+')
62 #define PRINT_ERROR ((opterr) && ((*options != ':') \
63  || (IGNORE_FIRST && options[1] != ':')))
64 #define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL)
65 #define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
66 /* XXX: GNU ignores PC if *options == '-' */
67 #define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-')
68 /* return values */
69 #define BADCH (int)'?'
70 #define BADARG (int)':'
71 #define INORDER (int)1
72 #define EMSG ""
73  static int getopt_internal (int, char *const *, const char *);
74  static int gcd (int, int);
75  static void permute_args (int, int, int, char *const *);
76  static void xwarnx (const char *, ...);
77 
78  static char *place = EMSG; /* option letter processing */
79 
80 /* XXX: set optreset to 1 rather than these two */
81  static int nonopt_start = -1; /* first non option argument (for permute) */
82  static int nonopt_end = -1; /* first option after non options (for permute) */
83 
84 /* Error messages */
85  static const char recargchar[] = "option requires an argument -- %c";
86  static const char recargstring[] = "option requires an argument -- %s";
87  static const char ambig[] = "ambiguous option -- %.*s";
88  static const char noarg[] = "option doesn't take an argument -- %.*s";
89  static const char illoptchar[] = "illegal option -- %c";
90  static const char illoptstring[] = "illegal option -- %s";
91 
92  static const char *progname;
93 
94 
95 /* Replacement for warnx(3) for systems without it. */
96  static void xwarnx (const char *fmt, ...)
97 {
98  va_list ap;
99 
100  va_start (ap, fmt);
101  if (progname)
102  (void) fprintf (stderr, "%s: ", progname);
103  if (fmt)
104  (void) vfprintf (stderr, fmt, ap);
105  (void) fprintf (stderr, "\n");
106  va_end (ap);
107 }
108 
109 /*
110  * Compute the greatest common divisor of a and b.
111  */
112 static int
113 gcd (int a, int b)
114 {
115  int c;
116 
117  c = a % b;
118  while (c != 0)
119  {
120  a = b;
121  b = c;
122  c = a % b;
123  }
124 
125  return b;
126 }
127 
128 /*
129  * Exchange the block from nonopt_start to nonopt_end with the block
130  * from nonopt_end to opt_end (keeping the same order of arguments
131  * in each block).
132  */
133 static void
134 permute_args (int nonopt_start, int nonopt_end, int opt_end, char *const *nargv)
135 {
136  int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
137  char *swap;
138 
139  /*
140  * compute lengths of blocks and number and size of cycles
141  */
142  nnonopts = nonopt_end - nonopt_start;
143  nopts = opt_end - nonopt_end;
144  ncycle = gcd (nnonopts, nopts);
145  cyclelen = (opt_end - nonopt_start) / ncycle;
146 
147  for (i = 0; i < ncycle; i++)
148  {
149  cstart = nonopt_end + i;
150  pos = cstart;
151  for (j = 0; j < cyclelen; j++)
152  {
153  if (pos >= nonopt_end)
154  pos -= nnonopts;
155  else
156  pos += nopts;
157  swap = nargv[pos];
158  /* LINTED const cast */
159  ((char **) nargv)[pos] = nargv[cstart];
160  /* LINTED const cast */
161  ((char **) nargv)[cstart] = swap;
162  }
163  }
164 }
165 
166 /*
167  * getopt_internal --
168  * Parse argc/argv argument vector. Called by user level routines.
169  * Returns -2 if -- is found (can be long option or end of options marker).
170  */
171 static int
172 getopt_internal (int nargc, char *const *nargv, const char *options)
173 {
174  char *oli; /* option letter list index */
175  int optchar;
176 
177  _DIAGASSERT (nargv != NULL);
178  _DIAGASSERT (options != NULL);
179 
180  optarg = NULL;
181 
182  /*
183  * XXX Some programs (like rsyncd) expect to be able to
184  * XXX re-initialize optind to 0 and have getopt_long(3)
185  * XXX properly function again. Work around this braindamage.
186  */
187  if (optind == 0)
188  optind = 1;
189 
190  if (optreset)
191  nonopt_start = nonopt_end = -1;
192 start:
193  if (optreset || !*place)
194  { /* update scanning pointer */
195  optreset = 0;
196  if (optind >= nargc)
197  { /* end of argument vector */
198  place = EMSG;
199  if (nonopt_end != -1)
200  {
201  /* do permutation, if we have to */
202  permute_args (nonopt_start, nonopt_end, optind, nargv);
203  optind -= nonopt_end - nonopt_start;
204  }
205  else if (nonopt_start != -1)
206  {
207  /*
208  * If we skipped non-options, set optind
209  * to the first of them.
210  */
211  optind = nonopt_start;
212  }
213  nonopt_start = nonopt_end = -1;
214  return -1;
215  }
216  if (*(place = nargv[optind]) != '-')
217  { /* found non-option */
218  place = EMSG;
219  if (IN_ORDER)
220  {
221  /*
222  * GNU extension:
223  * return non-option as argument to option 1
224  */
225  optarg = nargv[optind++];
226  return INORDER;
227  }
228  if (!PERMUTE)
229  {
230  /*
231  * if no permutation wanted, stop parsing
232  * at first non-option
233  */
234  return -1;
235  }
236  /* do permutation */
237  if (nonopt_start == -1)
238  nonopt_start = optind;
239  else if (nonopt_end != -1)
240  {
241  permute_args (nonopt_start, nonopt_end, optind, nargv);
242  nonopt_start = optind - (nonopt_end - nonopt_start);
243  nonopt_end = -1;
244  }
245  optind++;
246  /* process next argument */
247  goto start;
248  }
249  if (nonopt_start != -1 && nonopt_end == -1)
250  nonopt_end = optind;
251  if (place[1] && *++place == '-')
252  { /* found "--" */
253  place++;
254  return -2;
255  }
256  }
257  if ((optchar = (int) *place++) == (int) ':' || (oli = (char *) strchr (options + (IGNORE_FIRST ? 1 : 0), optchar))
258  == NULL)
259  {
260  /* option letter unknown or ':' */
261  if (!*place)
262  ++optind;
263  if (PRINT_ERROR)
264  xwarnx (illoptchar, optchar);
265  optopt = optchar;
266  return BADCH;
267  }
268  if (optchar == 'W' && oli[1] == ';')
269  { /* -W long-option */
270  /* XXX: what if no long options provided (called by getopt)? */
271  if (*place)
272  return -2;
273 
274  if (++optind >= nargc)
275  { /* no arg */
276  place = EMSG;
277  if (PRINT_ERROR)
278  xwarnx (recargchar, optchar);
279  optopt = optchar;
280  /* XXX: GNU returns '?' if options[0] != ':' */
281  return BADARG;
282  }
283  else /* white space */
284  place = nargv[optind];
285  /*
286  * Handle -W arg the same as --arg (which causes getopt to
287  * stop parsing).
288  */
289  return -2;
290  }
291  if (*++oli != ':')
292  { /* doesn't take argument */
293  if (!*place)
294  ++optind;
295  }
296  else
297  { /* takes (optional) argument */
298  optarg = NULL;
299  if (*place) /* no white space */
300  optarg = place;
301  /* XXX: disable test for :: if PC? (GNU doesn't) */
302  else if (oli[1] != ':')
303  { /* arg not optional */
304  if (++optind >= nargc)
305  { /* no arg */
306  place = EMSG;
307  if (PRINT_ERROR)
308  xwarnx (recargchar, optchar);
309  optopt = optchar;
310  /* XXX: GNU returns '?' if options[0] != ':' */
311  return BADARG;
312  }
313  else
314  optarg = nargv[optind];
315  }
316  place = EMSG;
317  ++optind;
318  }
319  /* dump back option letter */
320  return optchar;
321 }
322 
323 #ifdef REPLACE_GETOPT
324 /*
325  * getopt --
326  * Parse argc/argv argument vector.
327  *
328  * [eventually this will replace the real getopt]
329  */
330 int
331 getopt (int nargc, char *const *nargv, const char *options)
332 {
333  int retval;
334 
335  progname = nargv[0];
336 
337  if ((retval = getopt_internal (nargc, nargv, options)) == -2)
338  {
339  ++optind;
340  /*
341  * We found an option (--), so if we skipped non-options,
342  * we have to permute.
343  */
344  if (nonopt_end != -1)
345  {
346  permute_args (nonopt_start, nonopt_end, optind, nargv);
347  optind -= nonopt_end - nonopt_start;
348  }
349  nonopt_start = nonopt_end = -1;
350  retval = -1;
351  }
352  return retval;
353 }
354 #endif
355 
356 /*
357  * getopt_long --
358  * Parse argc/argv argument vector.
359  */
360 int
361 getopt_long (int nargc, char *const *nargv, const char *options, const struct option *long_options, int *idx)
362 {
363  int retval;
364 
365  _DIAGASSERT (nargv != NULL);
366  _DIAGASSERT (options != NULL);
367  _DIAGASSERT (long_options != NULL);
368  /* idx may be NULL */
369 
370  progname = nargv[0];
371 
372  if ((retval = getopt_internal (nargc, nargv, options)) == -2)
373  {
374  char *current_argv, *has_equal;
375  size_t current_argv_len;
376  int i, match;
377 
378  current_argv = place;
379  match = -1;
380 
381  optind++;
382  place = EMSG;
383 
384  if (*current_argv == '\0')
385  { /* found "--" */
386  /*
387  * We found an option (--), so if we skipped
388  * non-options, we have to permute.
389  */
390  if (nonopt_end != -1)
391  {
392  permute_args (nonopt_start, nonopt_end, optind, nargv);
393  optind -= nonopt_end - nonopt_start;
394  }
395  nonopt_start = nonopt_end = -1;
396  return -1;
397  }
398  if ((has_equal = strchr (current_argv, '=')) != NULL)
399  {
400  /* argument found (--option=arg) */
401  current_argv_len = has_equal - current_argv;
402  has_equal++;
403  }
404  else
405  current_argv_len = strlen (current_argv);
406 
407  for (i = 0; long_options[i].name; i++)
408  {
409  /* find matching long option */
410  if (strncmp (current_argv, long_options[i].name, current_argv_len))
411  continue;
412 
413  if (strlen (long_options[i].name) == (unsigned) current_argv_len)
414  {
415  /* exact match */
416  match = i;
417  break;
418  }
419  if (match == -1) /* partial match */
420  match = i;
421  else
422  {
423  /* ambiguous abbreviation */
424  if (PRINT_ERROR)
425  xwarnx (ambig, (int) current_argv_len, current_argv);
426  optopt = 0;
427  return BADCH;
428  }
429  }
430  if (match != -1)
431  { /* option found */
432  if (long_options[match].has_arg == no_argument && has_equal)
433  {
434  if (PRINT_ERROR)
435  xwarnx (noarg, (int) current_argv_len, current_argv);
436  /*
437  * XXX: GNU sets optopt to val regardless of
438  * flag
439  */
440  if (long_options[match].flag == NULL)
441  optopt = long_options[match].val;
442  else
443  optopt = 0;
444  /* XXX: GNU returns '?' if options[0] != ':' */
445  return BADARG;
446  }
447  if (long_options[match].has_arg == required_argument || long_options[match].has_arg == optional_argument)
448  {
449  if (has_equal)
450  optarg = has_equal;
451  else if (long_options[match].has_arg == required_argument)
452  {
453  /*
454  * optional argument doesn't use
455  * next nargv
456  */
457  optarg = nargv[optind++];
458  }
459  }
460  if ((long_options[match].has_arg == required_argument) && (optarg == NULL))
461  {
462  /*
463  * Missing argument; leading ':'
464  * indicates no error should be generated
465  */
466  if (PRINT_ERROR)
467  xwarnx (recargstring, current_argv);
468  /*
469  * XXX: GNU sets optopt to val regardless
470  * of flag
471  */
472  if (long_options[match].flag == NULL)
473  optopt = long_options[match].val;
474  else
475  optopt = 0;
476  /* XXX: GNU returns '?' if options[0] != ':' */
477  --optind;
478  return BADARG;
479  }
480  }
481  else
482  { /* unknown option */
483  if (PRINT_ERROR)
484  xwarnx (illoptstring, current_argv);
485  optopt = 0;
486  return BADCH;
487  }
488  if (long_options[match].flag)
489  {
490  *long_options[match].flag = long_options[match].val;
491  retval = 0;
492  }
493  else
494  retval = long_options[match].val;
495  if (idx)
496  *idx = match;
497  }
498  return retval;
499 }
500 #endif /* !HAVE_GETOPT_LONG */
static const char recargchar[]
#define IGNORE_FIRST
static int nonopt_start
static char * place
char * optarg
static int nonopt_end
int getopt_long(int nargc, char *const *nargv, const char *options, const struct option *long_options, int *idx)
#define PERMUTE
int optreset
static void xwarnx(const char *,...)
#define IN_ORDER
int optind
static const char illoptchar[]
#define required_argument
Definition: cubrid_getopt.h:50
static const char * progname
static const char illoptstring[]
#define INORDER
int opterr
#define optional_argument
Definition: cubrid_getopt.h:51
static const char recargstring[]
#define BADCH
#define no_argument
Definition: cubrid_getopt.h:49
static int getopt_internal(int, char *const *, const char *)
const char * name
Definition: cubrid_getopt.h:56
#define NULL
Definition: freelistheap.h:34
#define PRINT_ERROR
static const char ambig[]
int * flag
Definition: cubrid_getopt.h:63
static int gcd(int, int)
#define _DIAGASSERT(e)
#define BADARG
#define strlen(s1)
Definition: intl_support.c:43
static void permute_args(int, int, int, char *const *)
int i
Definition: dynamic_load.c:954
#define EMSG
static const char noarg[]
int optopt
int has_arg
Definition: cubrid_getopt.h:61
int getopt(int nargc, char *const *nargv, const char *options)