140 lines
4.7 KiB
C
140 lines
4.7 KiB
C
#pragma once
|
|
|
|
/*
|
|
This File was taken from https://github.com/attractivechaos/klib/blob/master/ketopt.h and is licensed under MIT license.
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
*/
|
|
|
|
#include <string.h> /* for strchr() and strncmp() */
|
|
|
|
#define ko_no_argument 0
|
|
#define ko_required_argument 1
|
|
#define ko_optional_argument 2
|
|
|
|
typedef struct {
|
|
int ind; /* equivalent to optind */
|
|
int opt; /* equivalent to optopt */
|
|
char *arg; /* equivalent to optarg */
|
|
int longidx; /* index of a long option; or -1 if short */
|
|
/* private variables not intended for external uses */
|
|
int i, pos, n_args;
|
|
} ketopt_t;
|
|
|
|
typedef struct {
|
|
const char *name;
|
|
int has_arg;
|
|
int val;
|
|
} ko_longopt_t;
|
|
|
|
static ketopt_t KETOPT_INIT = { 1, 0, 0, -1, 1, 0, 0 };
|
|
|
|
static void ketopt_permute(char *argv[], int j, int n) /* move argv[j] over n elements to the left */
|
|
{
|
|
int k;
|
|
char *p = argv[j];
|
|
for (k = 0; k < n; ++k)
|
|
argv[j - k] = argv[j - k - 1];
|
|
argv[j - k] = p;
|
|
}
|
|
|
|
/**
|
|
* Parse command-line options and arguments
|
|
*
|
|
* This fuction has a similar interface to GNU's getopt_long(). Each call
|
|
* parses one option and returns the option name. s->arg points to the option
|
|
* argument if present. The function returns -1 when all command-line arguments
|
|
* are parsed. In this case, s->ind is the index of the first non-option
|
|
* argument.
|
|
*
|
|
* @param s status; shall be initialized to KETOPT_INIT on the first call
|
|
* @param argc length of argv[]
|
|
* @param argv list of command-line arguments; argv[0] is ignored
|
|
* @param permute non-zero to move options ahead of non-option arguments
|
|
* @param ostr option string
|
|
* @param longopts long options
|
|
*
|
|
* @return ASCII for a short option; ko_longopt_t::val for a long option; -1 if
|
|
* argv[] is fully processed; '?' for an unknown option or an ambiguous
|
|
* long option; ':' if an option argument is missing
|
|
*/
|
|
static int ketopt(ketopt_t *s, int argc, char *argv[], int permute, const char *ostr, const ko_longopt_t *longopts)
|
|
{
|
|
int opt = -1, i0, j;
|
|
if (permute) {
|
|
while (s->i < argc && (argv[s->i][0] != '-' || argv[s->i][1] == '\0'))
|
|
++s->i, ++s->n_args;
|
|
}
|
|
s->arg = 0, s->longidx = -1, i0 = s->i;
|
|
if (s->i >= argc || argv[s->i][0] != '-' || argv[s->i][1] == '\0') {
|
|
s->ind = s->i - s->n_args;
|
|
return -1;
|
|
}
|
|
if (argv[s->i][0] == '-' && argv[s->i][1] == '-') { /* "--" or a long option */
|
|
if (argv[s->i][2] == '\0') { /* a bare "--" */
|
|
ketopt_permute(argv, s->i, s->n_args);
|
|
++s->i, s->ind = s->i - s->n_args;
|
|
return -1;
|
|
}
|
|
s->opt = 0, opt = '?', s->pos = -1;
|
|
if (longopts) { /* parse long options */
|
|
int k, n_matches = 0;
|
|
const ko_longopt_t *o = 0;
|
|
for (j = 2; argv[s->i][j] != '\0' && argv[s->i][j] != '='; ++j) {} /* find the end of the option name */
|
|
for (k = 0; longopts[k].name != 0; ++k)
|
|
if (strncmp(&argv[s->i][2], longopts[k].name, j - 2) == 0)
|
|
++n_matches, o = &longopts[k];
|
|
if (n_matches == 1) {
|
|
s->opt = opt = o->val, s->longidx = (int)(o - longopts);
|
|
if (argv[s->i][j] == '=') s->arg = &argv[s->i][j + 1];
|
|
if (o->has_arg == 1 && argv[s->i][j] == '\0') {
|
|
if (s->i < argc - 1) s->arg = argv[++s->i];
|
|
else opt = ':'; /* missing option argument */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else { /* a short option */
|
|
const char *p;
|
|
if (s->pos == 0) s->pos = 1;
|
|
opt = s->opt = argv[s->i][s->pos++];
|
|
p = strchr(ostr, opt);
|
|
if (p == 0) {
|
|
opt = '?'; /* unknown option */
|
|
}
|
|
else if (p[1] == ':') {
|
|
if (argv[s->i][s->pos] == 0) {
|
|
if (s->i < argc - 1) s->arg = argv[++s->i];
|
|
else opt = ':'; /* missing option argument */
|
|
}
|
|
else s->arg = &argv[s->i][s->pos];
|
|
s->pos = -1;
|
|
}
|
|
}
|
|
if (s->pos < 0 || argv[s->i][s->pos] == 0) {
|
|
++s->i, s->pos = 0;
|
|
if (s->n_args > 0) /* permute */
|
|
for (j = i0; j < s->i; ++j)
|
|
ketopt_permute(argv, j, s->n_args);
|
|
}
|
|
s->ind = s->i - s->n_args;
|
|
return opt;
|
|
}
|