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