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  * $PostgreSQL: pgsql/src/port/getopt_long.c,v 1.8 2009-06-11 14:49:15 momjian Exp $
35  */
36 
37 #include <stdio.h>
38 #include <string.h>
39 #include "utils/getopt_long.h"
40 
41 #ifndef HAVE_INT_OPTRESET
42 int			optreset;
43 
44 /* else the "extern" was provided by getopt_long.h */
45 #endif
46 
47 #define BADCH	'?'
48 #define BADARG	':'
49 #define EMSG	""
50 
51 
52 int
getopt_long(int argc,char * const argv[],const char * optstring,const struct option * longopts,int * longindex)53 getopt_long(int argc, char *const argv[],
54 			const char *optstring,
55 			const struct option *longopts, int *longindex)
56 {
57 	static char *place = EMSG;	/* option letter processing */
58 	char	   *oli;			/* option letter list index */
59 
60 	if (optreset || !*place)
61 	{							/* update scanning pointer */
62 		optreset = 0;
63 
64 		if (optind >= argc)
65 		{
66 			place = EMSG;
67 			return -1;
68 		}
69 
70 		place = argv[optind];
71 
72 		if (place[0] != '-')
73 		{
74 			place = EMSG;
75 			return -1;
76 		}
77 
78 		place++;
79 
80 		if (place[0] && place[0] == '-' && place[1] == '\0')
81 		{						/* found "--" */
82 			++optind;
83 			place = EMSG;
84 			return -1;
85 		}
86 
87 		if (place[0] && place[0] == '-' && place[1])
88 		{
89 			/* long option */
90 			size_t		namelen;
91 			int			i;
92 
93 			place++;
94 
95 			namelen = strcspn(place, "=");
96 			for (i = 0; longopts[i].name != NULL; i++)
97 			{
98 				if (strlen(longopts[i].name) == namelen
99 					&& strncmp(place, longopts[i].name, namelen) == 0)
100 				{
101 					if (longopts[i].has_arg)
102 					{
103 						if (place[namelen] == '=')
104 							optarg = place + namelen + 1;
105 						else if (optind < argc - 1)
106 						{
107 							optind++;
108 							optarg = argv[optind];
109 						}
110 						else
111 						{
112 							if (optstring[0] == ':')
113 								return BADARG;
114 							if (opterr)
115 								fprintf(stderr,
116 										"%s: option requires an argument -- %s\n",
117 										argv[0], place);
118 							place = EMSG;
119 							optind++;
120 							return BADCH;
121 						}
122 					}
123 					else
124 					{
125 						optarg = NULL;
126 						if (place[namelen] != 0)
127 						{
128 							/* XXX error? */
129 						}
130 					}
131 
132 					optind++;
133 
134 					if (longindex)
135 						*longindex = i;
136 
137 					place = EMSG;
138 
139 					if (longopts[i].flag == NULL)
140 						return longopts[i].val;
141 					else
142 					{
143 						*longopts[i].flag = longopts[i].val;
144 						return 0;
145 					}
146 				}
147 			}
148 
149 			if (opterr && optstring[0] != ':')
150 				fprintf(stderr,
151 						"%s: illegal option -- %s\n", argv[0], place);
152 			place = EMSG;
153 			optind++;
154 			return BADCH;
155 		}
156 	}
157 
158 	/* short option */
159 	optopt = (int) *place++;
160 
161 	oli = strchr(optstring, optopt);
162 	if (!oli)
163 	{
164 		if (!*place)
165 			++optind;
166 		if (opterr && *optstring != ':')
167 			fprintf(stderr,
168 					"%s: illegal option -- %c\n", argv[0], optopt);
169 		return BADCH;
170 	}
171 
172 	if (oli[1] != ':')
173 	{							/* don't need argument */
174 		optarg = NULL;
175 		if (!*place)
176 			++optind;
177 	}
178 	else
179 	{							/* need an argument */
180 		if (*place)				/* no white space */
181 			optarg = place;
182 		else if (argc <= ++optind)
183 		{						/* no arg */
184 			place = EMSG;
185 			if (*optstring == ':')
186 				return BADARG;
187 			if (opterr)
188 				fprintf(stderr,
189 						"%s: option requires an argument -- %c\n",
190 						argv[0], optopt);
191 			return BADCH;
192 		}
193 		else
194 			/* white space */
195 			optarg = argv[optind];
196 		place = EMSG;
197 		++optind;
198 	}
199 	return optopt;
200 }
201