0/* Copyright (c) 2012, Kim Gräsman
1 * All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
5 * * Redistributions of source code must retain the above copyright notice,
6 * this list of conditions and the following disclaimer.
7 * * Redistributions in binary form must reproduce the above copyright notice,
8 * this list of conditions and the following disclaimer in the documentation
9 * and/or other materials provided with the distribution.
10 * * Neither the name of Kim Gräsman nor the names of contributors may be used
11 * to endorse or promote products derived from this software without specific
12 * prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL KIM GRÄSMAN BE LIABLE FOR ANY DIRECT,
18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
26#include "getopt.h"
28#include <stddef.h>
29#include <string.h>
31const int no_argument = 0;
32const int required_argument = 1;
33const int optional_argument = 2;
35char* optarg;
36int optopt;
37/* The variable optind [...] shall be initialized to 1 by the system. */
38int optind = 1;
39int opterr;
41static char* optcursor = NULL;
43/* Implemented based on [1] and [2] for optional arguments.
44 optopt is handled FreeBSD-style, per [3].
45 Other GNU and FreeBSD extensions are purely accidental.
47[1] http://pubs.opengroup.org/onlinepubs/000095399/functions/getopt.html
48[2] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html
49[3] http://www.freebsd.org/cgi/man.cgi?query=getopt&sektion=3&manpath=FreeBSD+9.0-RELEASE
50*/
51int getopt(int argc, char* const argv[], const char* optstring) {
52 int optchar = -1;
53 const char* optdecl = NULL;
55 optarg = NULL;
56 opterr = 0;
57 optopt = 0;
59 /* Unspecified, but we need it to avoid overrunning the argv bounds. */
60 if (optind >= argc)
61 goto no_more_optchars;
63 /* If, when getopt() is called argv[optind] is a null pointer, getopt()
64 shall return -1 without changing optind. */
65 if (argv[optind] == NULL)
66 goto no_more_optchars;
68 /* If, when getopt() is called *argv[optind] is not the character '-',
69 getopt() shall return -1 without changing optind. */
70 if (*argv[optind] != '-')
71 goto no_more_optchars;
73 /* If, when getopt() is called argv[optind] points to the string "-",
74 getopt() shall return -1 without changing optind. */
75 if (strcmp(argv[optind], "-") == 0)
76 goto no_more_optchars;
78 /* If, when getopt() is called argv[optind] points to the string "--",
79 getopt() shall return -1 after incrementing optind. */
80 if (strcmp(argv[optind], "--") == 0) {
81 ++optind;
82 goto no_more_optchars;
83 }
85 if (optcursor == NULL || *optcursor == '\0')
86 optcursor = argv[optind] + 1;
88 optchar = *optcursor;
90 /* FreeBSD: The variable optopt saves the last known option character
91 returned by getopt(). */
92 optopt = optchar;
94 /* The getopt() function shall return the next option character (if one is
95 found) from argv that matches a character in optstring, if there is
96 one that matches. */
97 optdecl = strchr(optstring, optchar);
98 if (optdecl) {
99 /* [I]f a character is followed by a colon, the option takes an
100 argument. */
101 if (optdecl[1] == ':') {
102 optarg = ++optcursor;
103 if (*optarg == '\0') {
104 /* GNU extension: Two colons mean an option takes an
105 optional arg; if there is text in the current argv-element
106 (i.e., in the same word as the option name itself, for example,
107 "-oarg"), then it is returned in optarg, otherwise optarg is set
108 to zero. */
109 if (optdecl[2] != ':') {
110 /* If the option was the last character in the string pointed to by
111 an element of argv, then optarg shall contain the next element
112 of argv, and optind shall be incremented by 2. If the resulting
113 value of optind is greater than argc, this indicates a missing
114 option-argument, and getopt() shall return an error indication.
116 Otherwise, optarg shall point to the string following the
117 option character in that element of argv, and optind shall be
118 incremented by 1.
119 */
120 if (++optind < argc) {
121 optarg = argv[optind];
122 } else {
123 /* If it detects a missing option-argument, it shall return the
124 colon character ( ':' ) if the first character of optstring
125 was a colon, or a question-mark character ( '?' ) otherwise.
126 */
127 optarg = NULL;
128 optchar = (optstring[0] == ':') ? ':' : '?';
129 }
130 } else {
131 optarg = NULL;
132 }
133 }
135 optcursor = NULL;
136 }
137 } else {
138 /* If getopt() encounters an option character that is not contained in
139 optstring, it shall return the question-mark ( '?' ) character. */
140 optchar = '?';
141 }
143 if (optcursor == NULL || *++optcursor == '\0')
144 ++optind;
146 return optchar;
148no_more_optchars:
149 optcursor = NULL;
150 return -1;
151}
153/* Implementation based on [1].
155[1] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html
156*/
157int getopt_long(int argc, char* const argv[], const char* optstring,
158 const struct option* longopts, int* longindex) {
159 const struct option* o = longopts;
160 const struct option* match = NULL;
161 int num_matches = 0;
162 size_t argument_name_length = 0;
163 const char* current_argument = NULL;
164 int retval = -1;
166 optarg = NULL;
167 optopt = 0;
169 if (optind >= argc)
170 return -1;
172 if (strlen(argv[optind]) < 3 || strncmp(argv[optind], "--", 2) != 0)
173 return getopt(argc, argv, optstring);
175 /* It's an option; starts with -- and is longer than two chars. */
176 current_argument = argv[optind] + 2;
177 argument_name_length = strcspn(current_argument, "=");
178 for (; o->name; ++o) {
179 if (strncmp(o->name, current_argument, argument_name_length) == 0) {
180 match = o;
181 ++num_matches;
182 }
183 }
185 if (num_matches == 1) {
186 /* If longindex is not NULL, it points to a variable which is set to the
187 index of the long option relative to longopts. */
188 if (longindex)
189 *longindex = (int) (match - longopts);
191 /* If flag is NULL, then getopt_long() shall return val.
192 Otherwise, getopt_long() returns 0, and flag shall point to a variable
193 which shall be set to val if the option is found, but left unchanged if
194 the option is not found. */
195 if (match->flag)
196 *(match->flag) = match->val;
198 retval = match->flag ? 0 : match->val;
200 if (match->has_arg != no_argument) {
201 optarg = strchr(argv[optind], '=');
202 if (optarg != NULL)
203 ++optarg;
205 if (match->has_arg == required_argument) {
206 /* Only scan the next argv for required arguments. Behavior is not
207 specified, but has been observed with Ubuntu and Mac OSX. */
208 if (optarg == NULL && ++optind < argc) {
209 optarg = argv[optind];
210 }
212 if (optarg == NULL)
213 retval = ':';
214 }
215 } else if (strchr(argv[optind], '=')) {
216 /* An argument was provided to a non-argument option.
217 I haven't seen this specified explicitly, but both GNU and BSD-based
218 implementations show this behavior.
219 */
220 retval = '?';
221 }
222 } else {
223 /* Unknown option or ambiguous match. */
224 retval = '?';
225 }
227 ++optind;
228 return retval;
229}
index : raylib-jai
---