CLI_Utils.cpp 3.32 KB
/*
 * CLI_Utils.cpp - CLI library for Arduino/ESP8266 and others utility functions
 *
 * Version 1.0, latest version, documentation and bugtracker available at:
 *              https://gitlab.lindenaar.net/arduino/CLI
 *
 * Copyright (c) 2019 Frederik Lindenaar
 *
 * This library is free software: you can redistribute it and/or modify it under
 * the terms of version 3 of the GNU General Public License as published by the
 * Free Software Foundation, or (at your option) a later version of the license.
 *
 * This code is distributed in the hope that it will be useful but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, visit <http://www.gnu.org/licenses/> to download it.
 */

#include <CLI.h>

const char *CLI_STR_skipSep(const char *str) {
  while (*str == ' ') str++;
  return str;
};

const char *CLI_STR_findSep(const char *str) {
  while (*str && *str != ' ') str++;
  return str;
};

const char *CLI_STR_parseInt(const char *str, int &value, int minvalue, int maxvalue) {
  int v = 0;
  const char *p = str;
  bool negative = *p == '-';
  if (negative || *p == '+') p++;
  while (*p >= '0' && *p <= '9') {
    v *= 10;
    v += *(p++) - '0';
  }
  if (str != p && v >= minvalue && v <= maxvalue) {
    value = (negative) ? -v : v;
    return p;
  }
  return 0;
}

uint8_t parseHexNibble(char c) {
  if(c >= 'a' && c <= 'f') {
    return c - 'a' + 10;
  } else if(c >= 'A' && c <= 'F') {
    return c - 'A' + 10;
  } else if(c >= '0' && c <= '9') {
    return c - '0';
  } else return 0xff;
}

const char *CLI_STR_parse_HEX_byte(const char *str, uint8_t &value) {
  if (str) {
    uint8_t v;
    if((v = parseHexNibble(*(str++))) <= 0xf) {
      value = v << 4;
      if((v = parseHexNibble(*(str++))) <= 0xf) {
        value |= v;
        return str;
      }
    }
  }
  return NULL;
}

const struct CLI_Command_Param *CLI_STR_parseParam_P (const char *param, const struct CLI_Command_Param params[]) {
  for (const struct CLI_Command_Param *p = params; pgm_read_ptr(&p->param); p++)
    if (!strcmp_P(param, (char *)pgm_read_ptr(&p->param))) return p;
  return NULL;
}

const char *CLI_STR_parseFlags_P (const char *str, const struct CLI_Command_Flags params[], uint8_t param_count, uint8_t mask, uint8_t *flags) {
  uint8_t f = 0;
  while (*str) {
    const struct CLI_Command_Flags *p = params;
    while (p <= &params[param_count] && strncmp_P(str, pgm_read_word(&p->command), pgm_read_byte(&p->cmdlen)) ) p++;
    uint8_t flags = pgm_read_byte(&p->flags);
    if (p > &params[param_count] || (f != 0 && ((f & mask) != (flags & mask)))) return 0;
    f |= flags;
    str = CLI_STR_skipSep(str + pgm_read_byte(&p->cmdlen));

    if (uint8_t intparam = pgm_read_byte(&p->intparam)) {
      int i;
      if (str = CLI_STR_parseInt(str, i)) {
        if (pgm_read_byte(&p->cmdlen) == 0)
          if (int divider = pgm_read_word(&p->command)) {
            i /= divider & 0xff;
            i += divider >> 8;
          }
        if (i <= (intparam & 0x1f)) {
          f |= i << (intparam >> 5);
          str = CLI_STR_skipSep(str);
          continue;
        }
      }
      return 0;
    }
  }
  if (*str) return 0;
  *flags = f;
  return str;
}