| 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
|