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 <stdio.h>
|
38 |
#include <string.h>
|
39 |
|
40 |
#include "getopt_long.h"
|
41 |
|
42 |
int opterr;
|
43 |
int optopt;
|
44 |
|
45 |
#define BADCH '?'
|
46 |
#define BADARG ':'
|
47 |
#define EMSG ""
|
48 |
|
49 |
|
50 |
/*
|
51 |
* getopt_long
|
52 |
* Parse argc/argv argument vector, with long options.
|
53 |
*
|
54 |
* This implementation does not use optreset. Instead, we guarantee that
|
55 |
* it can be restarted on a new argv array after a previous call returned -1,
|
56 |
* if the caller resets optind to 1 before the first call of the new series.
|
57 |
* (Internally, this means we must be sure to reset "place" to EMSG before
|
58 |
* returning -1.)
|
59 |
*/
|
60 |
int
|
61 |
getopt_long(int argc, char *const argv[],
|
62 |
const char *optstring,
|
63 |
const struct option * longopts, int *longindex)
|
64 |
{
|
65 |
static char *place = EMSG; /* option letter processing */
|
66 |
char *oli; /* option letter list index */
|
67 |
|
68 |
if (!*place)
|
69 |
{ /* update scanning pointer */
|
70 |
if (optind >= argc)
|
71 |
{
|
72 |
place = EMSG;
|
73 |
return -1;
|
74 |
}
|
75 |
|
76 |
place = argv[optind];
|
77 |
|
78 |
if (place[0] != '-')
|
79 |
{
|
80 |
place = EMSG;
|
81 |
return -1;
|
82 |
}
|
83 |
|
84 |
place++;
|
85 |
|
86 |
if (place[0] && place[0] == '-' && place[1] == '\0')
|
87 |
{ /* found "--" */
|
88 |
++optind;
|
89 |
place = EMSG;
|
90 |
return -1;
|
91 |
}
|
92 |
|
93 |
if (place[0] && place[0] == '-' && place[1])
|
94 |
{
|
95 |
/* long option */
|
96 |
size_t namelen;
|
97 |
int i;
|
98 |
|
99 |
place++;
|
100 |
|
101 |
namelen = strcspn(place, "=");
|
102 |
for (i = 0; longopts[i].name != NULL; i++)
|
103 |
{
|
104 |
if (strlen(longopts[i].name) == namelen
|
105 |
&& strncmp(place, longopts[i].name, namelen) == 0)
|
106 |
{
|
107 |
if (longopts[i].has_arg)
|
108 |
{
|
109 |
if (place[namelen] == '=')
|
110 |
optarg = place + namelen + 1;
|
111 |
else if (optind < argc - 1)
|
112 |
{
|
113 |
optind++;
|
114 |
optarg = argv[optind];
|
115 |
}
|
116 |
else
|
117 |
{
|
118 |
if (optstring[0] == ':')
|
119 |
return BADARG;
|
120 |
if (opterr)
|
121 |
fprintf(stderr,
|
122 |
"%s: option requires an argument -- %s\n",
|
123 |
argv[0], place);
|
124 |
place = EMSG;
|
125 |
optind++;
|
126 |
return BADCH;
|
127 |
}
|
128 |
}
|
129 |
else
|
130 |
{
|
131 |
optarg = NULL;
|
132 |
if (place[namelen] != 0)
|
133 |
{
|
134 |
/* XXX error? */
|
135 |
}
|
136 |
}
|
137 |
|
138 |
optind++;
|
139 |
|
140 |
if (longindex)
|
141 |
*longindex = i;
|
142 |
|
143 |
place = EMSG;
|
144 |
|
145 |
if (longopts[i].flag == NULL)
|
146 |
return longopts[i].val;
|
147 |
else
|
148 |
{
|
149 |
*longopts[i].flag = longopts[i].val;
|
150 |
return 0;
|
151 |
}
|
152 |
}
|
153 |
}
|
154 |
|
155 |
if (opterr && optstring[0] != ':')
|
156 |
fprintf(stderr,
|
157 |
"%s: illegal option -- %s\n", argv[0], place);
|
158 |
place = EMSG;
|
159 |
optind++;
|
160 |
return BADCH;
|
161 |
}
|
162 |
}
|
163 |
|
164 |
/* short option */
|
165 |
optopt = (int) *place++;
|
166 |
|
167 |
oli = strchr(optstring, optopt);
|
168 |
if (!oli)
|
169 |
{
|
170 |
if (!*place)
|
171 |
++optind;
|
172 |
if (opterr && *optstring != ':')
|
173 |
fprintf(stderr,
|
174 |
"%s: illegal option -- %c\n", argv[0], optopt);
|
175 |
return BADCH;
|
176 |
}
|
177 |
|
178 |
if (oli[1] != ':')
|
179 |
{ /* don't need argument */
|
180 |
optarg = NULL;
|
181 |
if (!*place)
|
182 |
++optind;
|
183 |
}
|
184 |
else
|
185 |
{ /* need an argument */
|
186 |
if (*place) /* no white space */
|
187 |
optarg = place;
|
188 |
else if (argc <= ++optind)
|
189 |
{ /* no arg */
|
190 |
place = EMSG;
|
191 |
if (*optstring == ':')
|
192 |
return BADARG;
|
193 |
if (opterr)
|
194 |
fprintf(stderr,
|
195 |
"%s: option requires an argument -- %c\n",
|
196 |
argv[0], optopt);
|
197 |
return BADCH;
|
198 |
}
|
199 |
else
|
200 |
/* white space */
|
201 |
optarg = argv[optind];
|
202 |
place = EMSG;
|
203 |
++optind;
|
204 |
}
|
205 |
return optopt;
|
206 |
}
|