xref: /6.0.3/platform/src/getopt.cc (revision 56295be6)
1/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 *     Copyright 2013 Couchbase, Inc.
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 */
17#define BUILDING_LIBPLATFORM 1
18#include <ctype.h>
19#include <platform/getopt.h>
20#include <stdio.h>
21#include <string.h>
22
23namespace cb {
24namespace getopt {
25
26char* optarg;
27int opterr;
28int optind = 1;
29int optopt;
30
31static int parse_longopt(int argc,
32                         char** argv,
33                         const struct option* longopts,
34                         int* longindex) {
35    const struct option* p;
36    char* name = argv[optind] + 2;
37    if (*name == '\0') {
38        ++optind;
39        return -1;
40    }
41
42    optarg = strchr(name, '=');
43    if (optarg == NULL) {
44        // value comes next!
45        optarg = argv[optind + 1];
46    } else {
47        *optarg = '\0';
48        ++optarg;
49    }
50
51    for (p = longopts; p != NULL && p->name; ++p) {
52        if (strcmp(name, p->name) == 0) {
53            // This is it :)
54            if (p->has_arg) {
55                // we need a value!
56                if (optarg == argv[optind + 1]) {
57                    ++optind;
58                }
59                if (optarg == NULL || optind >= argc) {
60                    fprintf(stderr,
61                            "%s: option requires an argument -- %s\n",
62                            argv[0],
63                            name);
64                    return '?';
65                }
66
67            } else {
68                optarg = NULL;
69                ++optind;
70            }
71            return p->val;
72        }
73    }
74
75    // Not found, we should increase optind too,
76    // to continue getopt_long().
77    optind++;
78    return '?';
79}
80
81int getopt_long(int argc,
82                char** argv,
83                const char* optstring,
84                const struct option* longopts,
85                int* longindex) {
86    if (optind + 1 > argc) {
87        // EOF
88        return -1;
89    }
90
91    if (argv[optind][0] != '-') {
92        return -1;
93    }
94
95    if (argv[optind][1] == '-') {
96        // this is a long option
97        return parse_longopt(argc, argv, longopts, longindex);
98    } else if (argv[optind][2] != '\0') {
99        fprintf(stderr,
100                "You can't specify multiple options with this "
101                "implementation\n");
102        return '?';
103    } else {
104        // this is a short option
105        const char* p = strchr(optstring, argv[optind][1]);
106        int idx = optind;
107        optind++;
108
109        if (p == NULL) {
110            return '?';
111        }
112
113        if (*(p + 1) == ':') {
114            optarg = argv[optind];
115            optind++;
116            if (optarg == NULL || optind > argc) {
117                fprintf(stderr,
118                        "%s: option requires an argument -- %s\n",
119                        argv[0],
120                        argv[idx] + 1);
121                return '?';
122            }
123        } else {
124            optarg = NULL;
125        }
126        return argv[idx][1];
127    }
128}
129
130int getopt(int argc, char** argv, const char* optstring) {
131    return getopt_long(argc, argv, optstring, NULL, NULL);
132}
133
134void reset() {
135    optarg = nullptr;
136    opterr = 0;
137    optind = 1;
138    optopt = 0;
139}
140} // namespace getopt
141} // namespace cb
142