blob: 8051a88397234e305e43b718ee380608bfa4d0b6 [file]
/**
* 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.
*/
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <stdarg.h>
#include <errno.h>
#include <assert.h>
#include "console/console.h"
#include "host/ble_uuid.h"
#include "bletiny_priv.h"
#define CMD_MAX_ARGS 16
static char *cmd_args[CMD_MAX_ARGS][2];
static int cmd_num_args;
void
print_addr(void *addr)
{
uint8_t *u8p;
u8p = addr;
BLETINY_LOG(INFO, "%02x:%02x:%02x:%02x:%02x:%02x",
u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]);
}
void
print_uuid(void *uuid128)
{
uint16_t uuid16;
uint8_t *u8p;
uuid16 = ble_uuid_128_to_16(uuid128);
if (uuid16 != 0) {
BLETINY_LOG(INFO, "0x%04x", uuid16);
return;
}
u8p = uuid128;
/* 00001101-0000-1000-8000-00805f9b34fb */
BLETINY_LOG(INFO, "%02x%02x%02x%02x-", u8p[15], u8p[14], u8p[13],
u8p[12]);
BLETINY_LOG(INFO, "%02x%02x-%02x%02x-", u8p[11], u8p[10], u8p[9], u8p[8]);
BLETINY_LOG(INFO, "%02x%02x%02x%02x%02x%02x%02x%02x",
u8p[7], u8p[6], u8p[5], u8p[4],
u8p[3], u8p[2], u8p[1], u8p[0]);
}
int
parse_err_too_few_args(char *cmd_name)
{
BLETINY_LOG(ERROR, "Error: too few arguments for command \"%s\"\n",
cmd_name);
return -1;
}
const struct cmd_entry *
parse_cmd_find(const struct cmd_entry *cmds, char *name)
{
const struct cmd_entry *cmd;
int i;
for (i = 0; cmds[i].name != NULL; i++) {
cmd = cmds + i;
if (strcmp(name, cmd->name) == 0) {
return cmd;
}
}
return NULL;
}
struct kv_pair *
parse_kv_find(struct kv_pair *kvs, char *name)
{
struct kv_pair *kv;
int i;
for (i = 0; kvs[i].key != NULL; i++) {
kv = kvs + i;
if (strcmp(name, kv->key) == 0) {
return kv;
}
}
return NULL;
}
char *
parse_arg_find(char *key)
{
int i;
for (i = 0; i < cmd_num_args; i++) {
if (strcmp(cmd_args[i][0], key) == 0) {
/* Erase parameter. */
cmd_args[i][0][0] = '\0';
return cmd_args[i][1];
}
}
return NULL;
}
long
parse_arg_long_bounds(char *name, long min, long max, int *out_status)
{
char *endptr;
char *sval;
long lval;
sval = parse_arg_find(name);
if (sval == NULL) {
*out_status = ENOENT;
return 0;
}
lval = strtol(sval, &endptr, 0);
if (sval[0] != '\0' && *endptr == '\0' &&
lval >= min && lval <= max) {
*out_status = 0;
return lval;
}
*out_status = EINVAL;
return 0;
}
long
parse_arg_long(char *name, int *out_status)
{
return parse_arg_long_bounds(name, LONG_MIN, LONG_MAX, out_status);
}
uint16_t
parse_arg_uint16(char *name, int *out_status)
{
return parse_arg_long_bounds(name, 0, UINT16_MAX, out_status);
}
uint32_t
parse_arg_uint32(char *name, int *out_status)
{
return parse_arg_long_bounds(name, 0, UINT32_MAX, out_status);
}
uint16_t
parse_arg_uint16_dflt(char *name, uint16_t dflt, int *out_status)
{
uint16_t val;
int rc;
val = parse_arg_uint16(name, &rc);
if (rc == ENOENT) {
val = dflt;
rc = 0;
}
*out_status = rc;
return val;
}
int
parse_arg_kv(char *name, struct kv_pair *kvs)
{
struct kv_pair *kv;
char *sval;
sval = parse_arg_find(name);
if (sval == NULL) {
return ENOENT;
}
kv = parse_kv_find(kvs, sval);
if (kv == NULL) {
return EINVAL;
}
return kv->val;
}
static int
parse_arg_byte_stream_no_delim(char *sval, int max_len, uint8_t *dst,
int *out_len)
{
unsigned long ul;
char *endptr;
char buf[3];
int i;
buf[2] = '\0';
i = 0;
while (1) {
if (sval[i * 2] == '\0') {
*out_len = i;
return 0;
}
if (i >= max_len) {
return EINVAL;
}
buf[0] = sval[i * 2 + 0];
buf[1] = sval[i * 2 + 1];
ul = strtoul(buf, &endptr, 16);
if (*sval == '\0' || *endptr != '\0') {
return EINVAL;
}
assert(ul <= UINT8_MAX);
dst[i] = ul;
i++;
}
}
static int
parse_arg_byte_stream_delim(char *sval, char *delims, int max_len,
uint8_t *dst, int *out_len)
{
unsigned long ul;
char *endptr;
char *token;
int i;
i = 0;
for (token = strtok(sval, delims);
token != NULL;
token = strtok(NULL, delims)) {
if (i >= max_len) {
return EINVAL;
}
ul = strtoul(token, &endptr, 16);
if (sval[0] == '\0' || *endptr != '\0' || ul > UINT8_MAX) {
return -1;
}
dst[i] = ul;
i++;
}
*out_len = i;
return 0;
}
int
parse_arg_byte_stream(char *name, int max_len, uint8_t *dst, int *out_len)
{
int total_len;
char *sval;
sval = parse_arg_find(name);
if (sval == NULL) {
return ENOENT;
}
total_len = strlen(sval);
if (strcspn(sval, ":-") == total_len) {
return parse_arg_byte_stream_no_delim(sval, max_len, dst, out_len);
} else {
return parse_arg_byte_stream_delim(sval, ":-", max_len, dst, out_len);
}
}
int
parse_arg_byte_stream_exact_length(char *name, uint8_t *dst, int len)
{
int actual_len;
int rc;
rc = parse_arg_byte_stream(name, 6, dst, &actual_len);
if (rc != 0) {
return rc;
}
if (actual_len != len) {
return EINVAL;
}
return 0;
}
static void
parse_reverse_bytes(uint8_t *bytes, int len)
{
uint8_t tmp;
int i;
for (i = 0; i < len / 2; i++) {
tmp = bytes[i];
bytes[i] = bytes[len - i - 1];
bytes[len - i - 1] = tmp;
}
}
int
parse_arg_mac(char *name, uint8_t *dst)
{
int rc;
rc = parse_arg_byte_stream_exact_length(name, dst, 6);
if (rc != 0) {
return rc;
}
parse_reverse_bytes(dst, 6);
return 0;
}
int
parse_arg_uuid(char *str, uint8_t *dst_uuid128)
{
uint16_t uuid16;
char *tok;
int rc;
uuid16 = parse_arg_uint16(str, &rc);
switch (rc) {
case ENOENT:
return ENOENT;
case 0:
rc = ble_uuid_16_to_128(uuid16, dst_uuid128);
if (rc != 0) {
return EINVAL;
} else {
return 0;
}
default:
/* e7add801-b042-4876-aae1112855353cc1 */
if (strlen(str) == 35) {
tok = strtok(str, "-");
if (tok == NULL) {
return EINVAL;
}
rc = parse_arg_byte_stream_exact_length(tok, dst_uuid128 + 0, 4);
if (rc != 0) {
return rc;
}
tok = strtok(NULL, "-");
if (tok == NULL) {
return EINVAL;
}
rc = parse_arg_byte_stream_exact_length(tok, dst_uuid128 + 4, 2);
if (rc != 0) {
return rc;
}
tok = strtok(NULL, "-");
if (tok == NULL) {
return EINVAL;
}
rc = parse_arg_byte_stream_exact_length(tok, dst_uuid128 + 6, 2);
if (rc != 0) {
return rc;
}
tok = strtok(NULL, "-");
if (tok == NULL) {
return EINVAL;
}
rc = parse_arg_byte_stream_exact_length(tok, dst_uuid128 + 8, 8);
if (rc != 0) {
return rc;
}
return 0;
}
rc = parse_arg_byte_stream_exact_length(str, dst_uuid128, 16);
return rc;
}
}
int
parse_arg_all(int argc, char **argv)
{
char *key;
char *val;
int i;
cmd_num_args = 0;
for (i = 0; i < argc; i++) {
key = strtok(argv[i], "=");
val = strtok(NULL, "=");
if (key != NULL && val != NULL) {
if (strlen(key) == 0) {
BLETINY_LOG(ERROR, "Error: invalid argument: %s\n", argv[i]);
return -1;
}
if (cmd_num_args >= CMD_MAX_ARGS) {
BLETINY_LOG(ERROR, "Error: too many arguments");
return -1;
}
cmd_args[cmd_num_args][0] = key;
cmd_args[cmd_num_args][1] = val;
cmd_num_args++;
}
}
return 0;
}