PostgreSQL Source Code  git master
getopt_long.c
Go to the documentation of this file.
1 /*
2  * getopt_long() -- long options parser
3  *
4  * Portions Copyright (c) 1987, 1993, 1994
5  * The Regents of the University of California. All rights reserved.
6  *
7  * Portions Copyright (c) 2003
8  * PostgreSQL Global Development Group
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in the
17  * documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  * may be used to endorse or promote products derived from this software
20  * without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  * src/port/getopt_long.c
35  */
36 
37 #include "c.h"
38 
39 #include "getopt_long.h"
40 
41 #define BADCH '?'
42 #define BADARG ':'
43 #define EMSG ""
44 
45 
46 /*
47  * getopt_long
48  * Parse argc/argv argument vector, with long options.
49  *
50  * This implementation does not use optreset. Instead, we guarantee that
51  * it can be restarted on a new argv array after a previous call returned -1,
52  * if the caller resets optind to 1 before the first call of the new series.
53  * (Internally, this means we must be sure to reset "place" to EMSG,
54  * "nonopt_start" to -1, and "force_nonopt" to false before returning -1.)
55  *
56  * Note that this routine reorders the pointers in argv (despite the const
57  * qualifier) so that all non-options will be at the end when -1 is returned.
58  */
59 int
60 getopt_long(int argc, char *const argv[],
61  const char *optstring,
62  const struct option *longopts, int *longindex)
63 {
64  static char *place = EMSG; /* option letter processing */
65  char *oli; /* option letter list index */
66  static int nonopt_start = -1;
67  static bool force_nonopt = false;
68 
69  if (!*place)
70  { /* update scanning pointer */
71  char **args = (char **) argv;
72 
73 retry:
74 
75  /*
76  * If we are out of arguments or only non-options remain, return -1.
77  */
78  if (optind >= argc || optind == nonopt_start)
79  {
80  place = EMSG;
81  nonopt_start = -1;
82  force_nonopt = false;
83  return -1;
84  }
85 
86  place = argv[optind];
87 
88  /*
89  * An argument is a non-option if it meets any of the following
90  * criteria: it follows an argument that is equivalent to the string
91  * "--", it does not start with '-', or it is equivalent to the string
92  * "-". When we encounter a non-option, we move it to the end of argv
93  * (after shifting all remaining arguments over to make room), and
94  * then we try again with the next argument.
95  */
96  if (force_nonopt || place[0] != '-' || place[1] == '\0')
97  {
98  for (int i = optind; i < argc - 1; i++)
99  args[i] = args[i + 1];
100  args[argc - 1] = place;
101 
102  if (nonopt_start == -1)
103  nonopt_start = argc - 1;
104  else
105  nonopt_start--;
106 
107  goto retry;
108  }
109 
110  place++;
111 
112  if (place[0] == '-' && place[1] == '\0')
113  {
114  /* found "--", treat it as end of options */
115  ++optind;
116  force_nonopt = true;
117  goto retry;
118  }
119 
120  if (place[0] == '-' && place[1])
121  {
122  /* long option */
123  size_t namelen;
124  int i;
125 
126  place++;
127 
128  namelen = strcspn(place, "=");
129  for (i = 0; longopts[i].name != NULL; i++)
130  {
131  if (strlen(longopts[i].name) == namelen
132  && strncmp(place, longopts[i].name, namelen) == 0)
133  {
134  int has_arg = longopts[i].has_arg;
135 
136  if (has_arg != no_argument)
137  {
138  if (place[namelen] == '=')
139  optarg = place + namelen + 1;
140  else if (optind < argc - 1 &&
141  has_arg == required_argument)
142  {
143  optind++;
144  optarg = argv[optind];
145  }
146  else
147  {
148  if (optstring[0] == ':')
149  return BADARG;
150 
151  if (opterr && has_arg == required_argument)
152  fprintf(stderr,
153  "%s: option requires an argument -- %s\n",
154  argv[0], place);
155 
156  place = EMSG;
157  optind++;
158 
159  if (has_arg == required_argument)
160  return BADCH;
161  optarg = NULL;
162  }
163  }
164  else
165  {
166  optarg = NULL;
167  if (place[namelen] != 0)
168  {
169  /* XXX error? */
170  }
171  }
172 
173  optind++;
174 
175  if (longindex)
176  *longindex = i;
177 
178  place = EMSG;
179 
180  if (longopts[i].flag == NULL)
181  return longopts[i].val;
182  else
183  {
184  *longopts[i].flag = longopts[i].val;
185  return 0;
186  }
187  }
188  }
189 
190  if (opterr && optstring[0] != ':')
191  fprintf(stderr,
192  "%s: illegal option -- %s\n", argv[0], place);
193  place = EMSG;
194  optind++;
195  return BADCH;
196  }
197  }
198 
199  /* short option */
200  optopt = (int) *place++;
201 
202  oli = strchr(optstring, optopt);
203  if (!oli)
204  {
205  if (!*place)
206  ++optind;
207  if (opterr && *optstring != ':')
208  fprintf(stderr,
209  "%s: illegal option -- %c\n", argv[0], optopt);
210  return BADCH;
211  }
212 
213  if (oli[1] != ':')
214  { /* don't need argument */
215  optarg = NULL;
216  if (!*place)
217  ++optind;
218  }
219  else
220  { /* need an argument */
221  if (*place) /* no white space */
222  optarg = place;
223  else if (argc <= ++optind)
224  { /* no arg */
225  place = EMSG;
226  if (*optstring == ':')
227  return BADARG;
228  if (opterr)
229  fprintf(stderr,
230  "%s: option requires an argument -- %c\n",
231  argv[0], optopt);
232  return BADCH;
233  }
234  else
235  /* white space */
236  optarg = argv[optind];
237  place = EMSG;
238  ++optind;
239  }
240  return optopt;
241 }
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition: getopt_long.c:60
#define BADCH
Definition: getopt_long.c:41
#define BADARG
Definition: getopt_long.c:42
#define EMSG
Definition: getopt_long.c:43
#define no_argument
Definition: getopt_long.h:24
#define required_argument
Definition: getopt_long.h:25
int i
Definition: isn.c:73
PGDLLIMPORT int optind
Definition: getopt.c:50
PGDLLIMPORT int optopt
Definition: getopt.c:51
PGDLLIMPORT int opterr
Definition: getopt.c:49
PGDLLIMPORT char * optarg
Definition: getopt.c:52
#define fprintf
Definition: port.h:242
int val
Definition: getopt_long.h:21
int has_arg
Definition: getopt_long.h:19
int * flag
Definition: getopt_long.h:20
const char * name
Definition: getopt_long.h:18
char * flag(int b)
Definition: test-ctype.c:33
const char * name