blob: 19e130068d267159329a88a2d0c3030aae39d1f9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* util/cmd: utility package for parsing `<key>=<value>` pairs among shell
* command arguments.
*/
#include <string.h>
#include <limits.h>
#include "defs/error.h"
#include "mn_socket/mn_socket.h"
#include "parse/parse.h"
#include "cmdarg/cmdarg.h"
/**
* Locates the index of the first '=' character in the provided string.
*/
static int
cmdarg_equals_off(const char *arg)
{
char *eq;
eq = strchr(arg, '=');
if (eq == NULL) {
return -1;
}
return eq - arg;
}
/**
* Given a key, finds the first argument with the following contents:
*
* <key>=[val]
*
* @param argc The argument count.
* @param argv The argument list.
* @param key The key to search for.
* @param out_val On success, points to the start of the located
* value string.
*
* @return Argument index on success; -1 on failure.
*/
static int
cmdarg_find_idx(int argc, char **argv, const char *key, char **out_val)
{
char *arg;
int eq_off;
int i;
for (i = 0; i < argc; i++) {
arg = argv[i];
if (arg != NULL) {
eq_off = cmdarg_equals_off(arg);
if (eq_off == -1) {
if (strcmp(arg, key) == 0) {
if (out_val != NULL) {
*out_val = NULL;
}
return i;
}
} else {
if (strncmp(arg, key, eq_off) == 0) {
if (out_val != NULL) {
*out_val = arg + eq_off + 1;
}
return i;
}
}
}
}
return -1;
}
static char *
cmdarg_find_priv(int argc, char **argv, const char *key, bool erase,
char **out_val)
{
char *arg;
int idx;
idx = cmdarg_find_idx(argc, argv, key, out_val);
if (idx == -1) {
return NULL;
}
arg = argv[idx];
if (erase) {
argv[idx] = NULL;
}
return arg;
}
char *
cmdarg_find(int argc, char **argv, const char *key, char **out_val)
{
return cmdarg_find_priv(argc, argv, key, false, out_val);
}
char *
cmdarg_extract(int argc, char **argv, const char *key, char **out_val)
{
return cmdarg_find_priv(argc, argv, key, true, out_val);
}
int
cmdarg_find_str(int argc, char **argv, const char *key, char **out_s)
{
const char *arg;
arg = cmdarg_find(argc, argv, key, out_s);
if (arg == NULL) {
return SYS_ENOENT;
}
return 0;
}
int
cmdarg_extract_str(int argc, char **argv, const char *key, char **out_s)
{
const char *arg;
arg = cmdarg_extract(argc, argv, key, out_s);
if (arg == NULL) {
return SYS_ENOENT;
}
return 0;
}
static int
cmdarg_find_ll_priv(int argc, char **argv, const char *name,
long long min, long long max, bool erase,
long long *out_ll)
{
const char *arg;
char *val;
long long ll;
int rc;
arg = cmdarg_find_priv(argc, argv, name, erase, &val);
if (arg == NULL) {
return SYS_ENOENT;
}
ll = parse_ll_bounds(val, min, max, &rc);
if (rc != 0) {
return rc;
}
if (out_ll != NULL) {
*out_ll = ll;
}
return 0;
}
int
cmdarg_find_ll(int argc, char **argv, const char *key,
long long min, long long max, long long *out_ll)
{
return cmdarg_find_ll_priv(argc, argv, key, min, max, false, out_ll);
}
int
cmdarg_extract_ll(int argc, char **argv, const char *key,
long long min, long long max, long long *out_ll)
{
return cmdarg_find_ll_priv(argc, argv, key, min, max, true, out_ll);
}
static int
cmdarg_find_ll_dflt_priv(int argc, char **argv, const char *key,
long long min, long long max, long long dflt,
bool erase, long long *out_ll)
{
int rc;
rc = cmdarg_find_ll_priv(argc, argv, key, min, max, erase, out_ll);
if (rc == SYS_ENOENT) {
rc = 0;
if (out_ll != NULL) {
*out_ll = dflt;
}
}
return rc;
}
int
cmdarg_find_ll_dflt(int argc, char **argv, const char *key,
long long min, long long max, long long dflt,
long long *out_ll)
{
return cmdarg_find_ll_dflt_priv(argc, argv, key, min, max, dflt, false,
out_ll);
}
int
cmdarg_extract_ll_dflt(int argc, char **argv, const char *key,
long long min, long long max, long long dflt,
long long *out_ll)
{
return cmdarg_find_ll_dflt_priv(argc, argv, key, min, max, dflt, true,
out_ll);
}
static int
cmdarg_find_ull_priv(int argc, char **argv, const char *key,
unsigned long long min, unsigned long long max,
bool erase, unsigned long long *out_ull)
{
unsigned long long ull;
const char *arg;
char *val;
int rc;
arg = cmdarg_find_priv(argc, argv, key, erase, &val);
if (arg == NULL) {
return SYS_ENOENT;
}
ull = parse_ull_bounds(val, min, max, &rc);
if (rc != 0) {
return rc;
}
if (out_ull != NULL) {
*out_ull = ull;
}
return 0;
}
int
cmdarg_find_ull(int argc, char **argv, const char *key,
unsigned long long min, unsigned long long max,
unsigned long long *out_ull)
{
return cmdarg_find_ull_priv(argc, argv, key, min, max, false, out_ull);
}
int
cmdarg_extract_ull(int argc, char **argv, const char *key,
unsigned long long min, unsigned long long max,
unsigned long long *out_ull)
{
return cmdarg_find_ull_priv(argc, argv, key, min, max, true, out_ull);
}
static int
cmdarg_find_ull_dflt_priv(int argc, char **argv, const char *key,
unsigned long long min, unsigned long long max,
unsigned long long dflt, bool erase,
unsigned long long *out_ull)
{
int rc;
rc = cmdarg_find_ull_priv(argc, argv, key, min, max, erase, out_ull);
if (rc == SYS_ENOENT) {
rc = 0;
if (out_ull != NULL) {
*out_ull = dflt;
}
}
return rc;
}
int
cmdarg_find_ull_dflt(int argc, char **argv, const char *key,
unsigned long long min, unsigned long long max,
unsigned long long dflt, unsigned long long *out_ull)
{
return cmdarg_find_ull_dflt_priv(argc, argv, key, min, max, dflt, false,
out_ull);
}
int
cmdarg_extract_ull_dflt(int argc, char **argv, const char *key,
unsigned long long min, unsigned long long max,
unsigned long long dflt, unsigned long long *out_ull)
{
return cmdarg_find_ull_dflt_priv(argc, argv, key, min, max, dflt,
true, out_ull);
}
static int
cmdarg_find_bool_priv(int argc, char **argv, const char *key, bool erase,
bool *out_b)
{
const char *arg;
char *val;
bool b;
int rc;
arg = cmdarg_find_priv(argc, argv, key, erase, &val);
if (arg == NULL) {
return SYS_ENOENT;
}
b = parse_bool(key, &rc);
if (rc != 0) {
return rc;
}
if (out_b != NULL) {
*out_b = b;
}
return 0;
}
int
cmdarg_find_bool(int argc, char **argv, const char *key, bool *out_b)
{
return cmdarg_find_bool_priv(argc, argv, key, false, out_b);
}
int
cmdarg_extract_bool(int argc, char **argv, const char *key, bool *out_b)
{
return cmdarg_find_bool_priv(argc, argv, key, true, out_b);
}
static int
cmdarg_find_bool_dflt_priv(int argc, char **argv, const char *key,
bool dflt, bool erase, bool *out_b)
{
int rc;
rc = cmdarg_find_bool_priv(argc, argv, key, erase, out_b);
if (rc == SYS_ENOENT) {
rc = 0;
if (out_b != NULL) {
*out_b = dflt;
}
}
return rc;
}
int
cmdarg_find_bool_dflt(int argc, char **argv, const char *key, bool dflt,
bool *out_b)
{
return cmdarg_find_bool_dflt_priv(argc, argv, key, dflt, false, out_b);
}
int
cmdarg_extract_bool_dflt(int argc, char **argv, const char *key, bool dflt,
bool *out_b)
{
return cmdarg_find_bool_dflt_priv(argc, argv, key, dflt, true, out_b);
}
static int
cmdarg_find_int_priv(int argc, char **argv, const char *key,
int min, int max, bool erase,
int *out_i)
{
long long ll;
int rc;
rc = cmdarg_find_ll_priv(argc, argv, key, min, max, erase, &ll);
if (rc == 0 && out_i != NULL) {
*out_i = ll;
}
return rc;
}
int
cmdarg_find_int(int argc, char **argv, const char *key, int min, int max,
int *out_i)
{
return cmdarg_find_int_priv(argc, argv, key, min, max, false, out_i);
}
int
cmdarg_extract_int(int argc, char **argv, const char *key, int min, int max,
int *out_i)
{
return cmdarg_find_int_priv(argc, argv, key, min, max, true, out_i);
}
static int
cmdarg_find_int_dflt_priv(int argc, char **argv, const char *key,
int min, int max, int dflt, bool erase,
int *out_i)
{
int rc;
rc = cmdarg_find_int_priv(argc, argv, key, min, max, erase, out_i);
if (rc == SYS_ENOENT) {
rc = 0;
if (out_i != NULL) {
*out_i = dflt;
}
}
return rc;
}
int
cmdarg_find_int_dflt(int argc, char **argv, const char *key,
int min, int max, int dflt,
int *out_i)
{
return cmdarg_find_int_dflt_priv(argc, argv, key, min, max, dflt, false,
out_i);
}
int
cmdarg_extract_int_dflt(int argc, char **argv, const char *key,
int min, int max, int dflt,
int *out_i)
{
return cmdarg_find_int_dflt_priv(argc, argv, key, min, max, dflt, true,
out_i);
}
static int
cmdarg_find_bytes_priv(int argc, char **argv, const char *key,
int max_len, bool erase,
uint8_t *out_val, int *out_len)
{
const char *arg;
char *val;
arg = cmdarg_find_priv(argc, argv, key, erase, &val);
if (arg == NULL) {
return SYS_ENOENT;
}
return parse_byte_stream(val, max_len, out_val, out_len);
}
int
cmdarg_find_bytes(int argc, char **argv, const char *key,
int max_len, uint8_t *out_val, int *out_len)
{
return cmdarg_find_bytes_priv(argc, argv, key, max_len, false, out_val,
out_len);
}
int
cmdarg_extract_bytes(int argc, char **argv, const char *key,
int max_len, uint8_t *out_val, int *out_len)
{
return cmdarg_find_bytes_priv(argc, argv, key, max_len, true, out_val,
out_len);
}
static int
cmdarg_find_eui_priv(int argc, char **argv, const char *key, bool erase,
uint8_t *out_eui)
{
const char *arg;
char *val;
arg = cmdarg_find_priv(argc, argv, key, erase, &val);
if (arg == NULL) {
return SYS_ENOENT;
}
return parse_byte_stream_exact_length_base(val, 16, out_eui, 8);
}
int
cmdarg_find_eui(int argc, char **argv, const char *key, uint8_t *out_eui)
{
return cmdarg_find_eui_priv(argc, argv, key, false, out_eui);
}
int
cmdarg_extract_eui(int argc, char **argv, const char *key, uint8_t *out_eui)
{
return cmdarg_find_eui_priv(argc, argv, key, true, out_eui);
}
static int
cmdarg_find_ip6_addr_priv(int argc, char **argv, const char *key,
bool erase, struct mn_in6_addr *out_addr)
{
struct mn_in6_addr addr;
const char *arg;
char *val;
int rc;
arg = cmdarg_find_priv(argc, argv, key, erase, &val);
if (arg == NULL) {
return SYS_ENOENT;
}
rc = mn_inet_pton(MN_AF_INET6, val, &addr);
if (rc != 1) {
return SYS_EINVAL;
}
if (out_addr != NULL) {
*out_addr = addr;
}
return 0;
}
int
cmdarg_find_ip6_addr(int argc, char **argv, const char *key,
struct mn_in6_addr *out_addr)
{
return cmdarg_find_ip6_addr_priv(argc, argv, key, false, out_addr);
}
int
cmdarg_extract_ip6_addr(int argc, char **argv, const char *key,
struct mn_in6_addr *out_addr)
{
return cmdarg_find_ip6_addr_priv(argc, argv, key, true, out_addr);
}
static int
cmdarg_find_ip6_net_priv(int argc, char **argv, const char *key,
bool erase, struct mn_in6_addr *out_addr,
uint8_t *out_prefix_len)
{
const char *arg;
char *val;
arg = cmdarg_find_priv(argc, argv, key, erase, &val);
if (arg == NULL || val == NULL) {
return SYS_ENOENT;
}
return parse_ip6_net(val, out_addr, out_prefix_len);
}
int
cmdarg_find_ip6_net(int argc, char **argv, const char *key,
struct mn_in6_addr *out_addr, uint8_t *out_prefix_len)
{
return cmdarg_find_ip6_net_priv(argc, argv, key, false, out_addr,
out_prefix_len);
}
int
cmdarg_extract_ip6_net(int argc, char **argv, const char *key,
struct mn_in6_addr *out_addr, uint8_t *out_prefix_len)
{
return cmdarg_find_ip6_net_priv(argc, argv, key, true, out_addr,
out_prefix_len);
}