// SPDX-License-Identifier: GPL-2.0
#include <linux/compiler.h>
#include <linux/string.h>
#include <linux/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <ctype.h>
#include "subcmd-util.h"
#include "parse-options.h"
#include "subcmd-config.h"
#include "pager.h"
#define OPT_SHORT 1
#define OPT_UNSET 2
char *error_buf;
static int opterror(const struct option *opt, const char *reason, int flags)
{
if (flags & OPT_SHORT)
fprintf(stderr, " Error: switch `%c' %s", opt->short_name, reason);
else if (flags & OPT_UNSET)
fprintf(stderr, " Error: option `no-%s' %s", opt->long_name, reason);
else
fprintf(stderr, " Error: option `%s' %s", opt->long_name, reason);
return -1;
}
static const char *skip_prefix(const char *str, const char *prefix)
{
size_t len = strlen(prefix);
return strncmp(str, prefix, len) ? NULL : str + len;
}
static void optwarning(const struct option *opt, const char *reason, int flags)
{
if (flags & OPT_SHORT)
fprintf(stderr, " Warning: switch `%c' %s", opt->short_name, reason);
else if (flags & OPT_UNSET)
fprintf(stderr, " Warning: option `no-%s' %s", opt->long_name, reason);
else
fprintf(stderr, " Warning: option `%s' %s", opt->long_name, reason);
}
static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
int flags, const char **arg)
{
const char *res;
if (p->opt) {
res = p->opt;
p->opt = NULL;
} else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
**(p->argv + 1) == '-')) {
res = (const char *)opt->defval;
} else if (p->argc > 1) {
p->argc--;
res = *++p->argv;
} else
return opterror(opt, "requires a value", flags);
if (arg)
*arg = res;
return 0;
}
static int get_value(struct parse_opt_ctx_t *p,
const struct option *opt, int flags)
{
const char *s, *arg = NULL;
const int unset = flags & OPT_UNSET;
int err;
if (unset && p->opt)
return opterror(opt, "takes no value", flags);
if (unset && (opt->flags & PARSE_OPT_NONEG))
return opterror(opt, "isn't available", flags);
if (opt->flags & PARSE_OPT_DISABLED)
return opterror(opt, "is not usable", flags);
if (opt->flags & PARSE_OPT_EXCLUSIVE) {
if (p->excl_opt && p->excl_opt != opt) {
char msg[128];
if (((flags & OPT_SHORT) && p->excl_opt->short_name) ||
p->excl_opt->long_name == NULL) {
snprintf(msg, sizeof(msg), "cannot be used with switch `%c'",
p->excl_opt->short_name);
} else {
snprintf(msg, sizeof(msg), "cannot be used with %s",
p->excl_opt->long_name);
}
opterror(opt, msg, flags);
return -3;
}
p->excl_opt = opt;
}
if (!(flags & OPT_SHORT) && p->opt) {
switch (opt->type) {
case OPTION_CALLBACK:
if (!(opt->flags & PARSE_OPT_NOARG))
break;
/* FALLTHROUGH */
case OPTION_BOOLEAN:
case OPTION_INCR:
case OPTION_BIT:
case OPTION_SET_UINT:
case OPTION_SET_PTR:
return opterror(opt, "takes no value", flags);
case OPTION_END:
case OPTION_ARGUMENT:
case OPTION_GROUP:
case OPTION_STRING:
case OPTION_INTEGER:
case OPTION_UINTEGER:
case OPTION_LONG:
case OPTION_ULONG:
case OPTION_U64:
default:
break;
}
}
if (opt->flags & PARSE_OPT_NOBUILD) {
char reason[128];
bool noarg = false;
err = snprintf(reason, sizeof(reason),
opt->flags & PARSE_OPT_CANSKIP ?
"is being ignored because %s " :
"is not available because %s",
opt->build_opt);
reason[sizeof(reason) - 1] = '\0';
if (err < 0)
strncpy(reason, opt->flags & PARSE_OPT_CANSKIP ?
"is being ignored" :
"is not available",
sizeof(reason));
if (!(opt->flags & PARSE_OPT_CANSKIP))
return opterror(opt, reason, flags);