1 | /*
|
2 | * Souffle - A Datalog Compiler
|
3 | * Copyright (c) 2022, The Souffle Developers. All rights reserved
|
4 | * Licensed under the Universal Permissive License v 1.0 as shown at:
|
5 | * - https://opensource.org/licenses/UPL
|
6 | * - <souffle root>/licenses/SOUFFLE-UPL.txt
|
7 | */
|
8 |
|
9 | // Implementation of getopt_long for Windows.
|
10 | #pragma once
|
11 | #ifdef USE_CUSTOM_GETOPTLONG
|
12 |
|
13 | #include "GetOptLong.h"
|
14 | #include <stdio.h>
|
15 | #include <string.h>
|
16 |
|
17 | char* optarg = nullptr;
|
18 |
|
19 | // the index of the next element to be processed in argv
|
20 | int optind = 0;
|
21 | int opterr = 1;
|
22 | int optopt = 0;
|
23 |
|
24 | enum { no_argument = 0, required_argument = 1, optional_argument = 2 };
|
25 |
|
26 | namespace {
|
27 |
|
28 | // nextchar points to the next option character in an element of argv
|
29 | char* nextchar = nullptr;
|
30 |
|
31 | // value of optind at the previous call of getopt_long
|
32 | int previous_optind = -1;
|
33 |
|
34 | // the number of non-options elements of argv skipped last time getopt was called
|
35 | int nonopt_count = 0;
|
36 |
|
37 | int parse_long_option(const int argc, char* const argv[], const struct option* longopts, int* longindex,
|
38 | const int print_error_message, const int missing_argument) {
|
39 | char* const current = nextchar;
|
40 | ++optind;
|
41 |
|
42 | char* const hasequal = strchr(current, '=');
|
43 | size_t namelength = (hasequal ? (hasequal - current) : strlen(current));
|
44 |
|
45 | int i;
|
46 | int match = -1;
|
47 | for (i = 0; longopts[i].name != nullptr; ++i) {
|
48 | if (strncmp(longopts[i].name, current, namelength)) {
|
49 | continue;
|
50 | }
|
51 | if (strlen(longopts[i].name) != namelength) {
|
52 | continue;
|
53 | }
|
54 |
|
55 | match = i;
|
56 | break;
|
57 | }
|
58 |
|
59 | if (match == -1) {
|
60 | // cannot find long option
|
61 | if (print_error_message) {
|
62 | fprintf(stderr, "unknown option -- %.*s\n", static_cast<int>(namelength), current);
|
63 | }
|
64 | optopt = 0;
|
65 | return (int)'?';
|
66 | }
|
67 |
|
68 | if (longopts[match].has_arg == no_argument) {
|
69 | // no argument expected
|
70 | if (hasequal) {
|
71 | if (print_error_message) {
|
72 | fprintf(stderr, "unexpected argument -- %.*s\n", static_cast<int>(namelength), current);
|
73 | }
|
74 | if (longopts[match].flag == nullptr) {
|
75 | optopt = longopts[match].val;
|
76 | } else {
|
77 | optopt = 0;
|
78 | }
|
79 | return (int)'?';
|
80 | }
|
81 | }
|
82 |
|
83 | if (longopts[match].has_arg == required_argument || longopts[match].has_arg == optional_argument) {
|
84 | if (hasequal) {
|
85 | // argument is in the same argv after '=' sign
|
86 | optarg = hasequal + 1;
|
87 | } else if (optind < argc) {
|
88 | // Argument may be in next argv
|
89 | // If argument is optional, leave optarg to null, user is in charge
|
90 | // of verifying the value of argv[optind] and increment optind
|
91 | // if the argument is valid.
|
92 | if (longopts[match].has_arg == required_argument) {
|
93 | // mandatory argument
|
94 | optarg = argv[optind++];
|
95 | }
|
96 | } else {
|
97 | // no argument found
|
98 | if (longopts[match].has_arg == required_argument) {
|
99 | if (print_error_message) {
|
100 | fprintf(stderr, "missing mandatory argument -- %.*s\n", static_cast<int>(namelength),
|
101 | current);
|
102 | }
|
103 | optopt = 0;
|
104 | return missing_argument;
|
105 | }
|
106 | }
|
107 | } // unexpected value of has_arg is not verified
|
108 |
|
109 | if (longindex) *longindex = match;
|
110 | if (longopts[match].flag) {
|
111 | *longopts[match].flag = longopts[match].val;
|
112 | return 0;
|
113 | } else {
|
114 | return longopts[match].val;
|
115 | }
|
116 | }
|
117 |
|
118 | // permute argv[last] and argv[last-1] and recurse
|
119 | void permute(char* argv[], int first, int last) {
|
120 | if (first >= last) return;
|
121 | char* tmp = argv[last];
|
122 | argv[last] = argv[last - 1];
|
123 | argv[last - 1] = tmp;
|
124 | permute(argv, first, last - 1);
|
125 | }
|
126 |
|
127 | void shift(char* argv[]) {
|
128 | // done with reading options from argv[previous_optind]..argv[optind-1]
|
129 |
|
130 | int start = previous_optind;
|
131 | for (int mv = previous_optind + nonopt_count; mv < optind; ++mv) {
|
132 | permute(argv, start, mv);
|
133 | ++start;
|
134 | }
|
135 |
|
136 | optind -= nonopt_count;
|
137 | previous_optind = optind;
|
138 | nonopt_count = 0;
|
139 | }
|
140 |
|
141 | } // anonymous namespace
|
142 |
|
143 | int getopt_long(
|
144 | int argc, char* const argv[], const char* optstring, const struct option* longopts, int* longindex) {
|
145 | if (optind == 0) { // full reset
|
146 | nextchar = nullptr;
|
147 | nonopt_count = 0;
|
148 | optarg = nullptr;
|
149 | optind = 1;
|
150 | previous_optind = optind;
|
151 | }
|
152 |
|
153 | int missing_argument = (int)'?';
|
154 | int print_error_message = opterr;
|
155 |
|
156 | optarg = nullptr;
|
157 |
|
158 | if (*optstring == '+' || *optstring == '-') {
|
159 | throw "Mode +/- of optstring is not supported.";
|
160 | ++optstring;
|
161 | }
|
162 |
|
163 | if (*optstring == ':') {
|
164 | missing_argument = (int)':';
|
165 | print_error_message = 0;
|
166 | ++optstring;
|
167 | }
|
168 |
|
169 | if (nextchar == nullptr) { // scan starting at argv[optind]
|
170 | if (nonopt_count > 0) { // previous scan skipped over some non-option arguments
|
171 | shift((char**)argv);
|
172 | } else {
|
173 | previous_optind = optind;
|
174 | }
|
175 | }
|
176 |
|
177 | if (optind >= argc) {
|
178 | // all command-line arguments have been scanned
|
179 | return -1;
|
180 | }
|
181 |
|
182 | if (nextchar == nullptr) { // scan starting at argv[optind], skip over any non-option elements
|
183 | while ((optind + nonopt_count < argc) &&
|
184 | (argv[optind + nonopt_count][0] != '-' || argv[optind + nonopt_count][1] == 0)) {
|
185 | ++nonopt_count;
|
186 | }
|
187 |
|
188 | if (optind + nonopt_count == argc) {
|
189 | // no more options
|
190 | nonopt_count = 0;
|
191 | return -1;
|
192 | }
|
193 |
|
194 | optind += nonopt_count;
|
195 | }
|
196 |
|
197 | if (nextchar == nullptr && optind < argc) { // scan starting at argv[optind]
|
198 | nextchar = argv[optind];
|
199 | }
|
200 |
|
201 | if (nextchar == argv[optind] && *nextchar == '-') {
|
202 | ++nextchar;
|
203 | if (*nextchar == '-' && nextchar[1] == 0) {
|
204 | // double-dash marks the end of the option scan
|
205 | nextchar = nullptr;
|
206 | shift((char**)argv);
|
207 | return -1;
|
208 | } else if (*nextchar == '-' && *(++nextchar)) {
|
209 | // search long option
|
210 | optopt =
|
211 | parse_long_option(argc, argv, longopts, longindex, print_error_message, missing_argument);
|
212 | nextchar = nullptr;
|
213 | return optopt;
|
214 | } else if (*nextchar == 0) {
|
215 | // missing option character
|
216 | optind += 1;
|
217 | nextchar = nullptr;
|
218 | return -1;
|
219 | }
|
220 | }
|
221 |
|
222 | // search short option
|
223 | const char* option;
|
224 | optopt = *nextchar++;
|
225 | if ((option = strchr(optstring, optopt)) == nullptr) {
|
226 | // cannot find option
|
227 | if (print_error_message) {
|
228 | fprintf(stderr, "unknown option -- %c\n", optopt);
|
229 | }
|
230 | return (int)'?';
|
231 | }
|
232 | ++option;
|
233 |
|
234 | if (*option++ != ':') {
|
235 | // no argument required
|
236 | if (!*nextchar) {
|
237 | ++optind;
|
238 | nextchar = nullptr;
|
239 | }
|
240 | } else {
|
241 | if (*nextchar) {
|
242 | // if argument is in the same argv, always set optarg
|
243 | optarg = nextchar;
|
244 | ++optind;
|
245 | nextchar = nullptr;
|
246 | } else if (argc <= ++optind) {
|
247 | // no argument found
|
248 | nextchar = nullptr;
|
249 | optarg = nullptr;
|
250 |
|
251 | if (*option != ':') {
|
252 | // mandatory argument is missing
|
253 | if (print_error_message) {
|
254 | fprintf(stderr, "missing mandatory argument -- %c\n", optopt);
|
255 | }
|
256 | return missing_argument;
|
257 | }
|
258 | } else {
|
259 | // argument is in next argv
|
260 | nextchar = nullptr;
|
261 |
|
262 | if (*option != ':' &&
|
263 | ((argv[optind][0] == '-' && (argv[optind][1] != 0 && argv[optind][1] != '-')) ||
|
264 | (argv[optind][0] == '-' && argv[optind][1] == '-' && argv[optind][2] != 0))) {
|
265 | // argument is mandatory, but must not start with a dash or a double-dash
|
266 | // or must be exactly dash or double-dash.
|
267 | if (print_error_message) {
|
268 | fprintf(stderr, "missing mandatory argument -- %c\n", optopt);
|
269 | }
|
270 | optarg = nullptr;
|
271 | return missing_argument;
|
272 | }
|
273 |
|
274 | if (*option != ':') {
|
275 | // argument is mandatory
|
276 | optarg = argv[optind++];
|
277 | } else {
|
278 | // Argument is optional but not in the same argv, set optarg to null.
|
279 | // User is in charge of interpreting argv[optind] and increment it
|
280 | // if it considers its a valid argument.
|
281 | optarg = nullptr;
|
282 | }
|
283 | }
|
284 | }
|
285 |
|
286 | return optopt;
|
287 | }
|
288 |
|
289 | #endif
|